Ce am mai înnoit la programele numerelor

Ca să nu mai dau de fiecare dată „g++ -m64 ... -lgmp -o ...” în linia de comandă de fiecare dată când schimb ceva într-un fișier cu cod-sursă, am pus mai multe programe să se recompileze singure și să se redeclanșeze așa, autocompilate, atunci când le dau drumul.

Am făcut asta:

-la ERMETE (care pornește actualizarea marilor fișiere numerice pe baza sortării în vectori de șiruri de caractere - char - a numerelor interpretate astfel);

-la ERMETE2 care face sortarea cu numerele luate ca tip de date mpz_t (întregii de la biblioteca GMP);

-la programele căutătoare de numere (principalele fiind NUMSIMPL, MODPRIME, HMODIFSUM, MODIFSUM și vecun, dar NU doar la ele, și și la nefolositele celelalte);

-la CARONTE, care are sarcina de a găsi numere prime noi în componența unor numere-depozit dintr-un interval dat, ca vectorul de numere prime corespunzător lor să fie îmbogățit cum se cuvine - plus, dintre primele deja existente, să stabilească dacă unele dintre cele cu care numerele-depozit sunt divizibile o singură dată au devenit între timp divizori de mai multe ori, ca să le mute în secțiunea cuvenită din fișierul de prime;

-la VARONTE, care șterge fișiere numerice perimate;

-la CREPITUS (ăsta este altă noutate, e destinat să construiască fișiere numerice mai mari, pe baza unora mai mici prealabile, fișiere-segment cu extensii definite);

-tot mai e loc de vorbit.

La VECUN am eliminat dualismul acela de căutare care presupunea două executabile separate - vecun simplu pentru când numerele de fond 1 din N3.TXT se obțin unele din altele prin înmulțire, respectiv vecun1 când trebuie împărțire.

Pentru o bună parte din programele de mai sus. nu doar că am pus la punct recompilarea automată, dar am mai îmbogățit lista lor de parametri dați din linia de comandă (argv), ca să le scriu direct acolo ce trebuie ele să facă și să NU mai tot stau să editez prin fișierele .cc pentru date noi de căutare. Așa încât editatul propriu-zis în conținutul unui fișier căutător (precum NUMSIMPL) se reduce acum la numele fișierului în care se vor aduna numere găsite (cu extensia .NUM2), iar aceste fișiere pot fi acum chiar și numai în rădăcina discului implicat, pentru că am lucrat și la mecanismele de redenumire ale fișierelor atunci când începe căutarea (și au extensia NUM2), se termină căutarea (din NUM2 devin NUM1) și când sunt sortate crescător numerele din ele (și din NUM1 devin NUM), așa încât dacă există deja un NUM2, NUM1 sau NUM  cu același nume, noul fișier venit să primească o schimbare (o cifră diferită sau în plus, eventual o literă dacă nu mai este loc de cifră în codul ASCII atins) în partea de dinainte de extensie.

În plus, la NUMSIMPL, MODPRIME și restul de căutătoare implicate, NU mai trebuie să tot stau acum să pun manual în ele o anume variabilă egală cu 1 (pentru căutări cu înmulțirea existentelor cu factorii de legătură, sau căutări în sus) ori 0 (pentru împărțiri, în jos), ci 1 sau 0 direct din linia de comandă, care NU este vreun Command Prompt că NU suntem pe Windows, dimpotrivă, din Guake în Linux*.

*Arch Linux pe MSISLI, ASUSPRIME, THREADRIPPER și... ăla micu alias Veritonul, pe când Aorusul și XPOWER-ul au Ubuntu 18.10 (pentru că Arch Linuxurile de pe ele au făcut fițe în decembrie).

***
Dar ce am făcut pentru recompilarea automată fișieristică?

Procedeul (ce cuvânt din limba de lemn...) este ca, prima dată, la lansarea manuală a executabilului din linia de comandă (cu parametrii ceruți), să se facă un g++ al acestuia (scris chiar înăuntru în fișierul *cc, manual, da, și executat cu clauza system() ), care va să zică lansarea unui al doilea executabil omonim din cadrul primului, și imediat din primul se face exit(), eventual return la main-ul care se termină cu return 0, și rămâne deșteptul de al doilea, care face restul trebii cerute.

Dar care este deosebirea dintre primul, cu g++ interiorizat, și al doilea, care rămâne?
Pentru că ele cumva trebuiesc deosebite.

Se întâmplă că pentru primul executabil dau litera „a” ca ultim parametru pentru argv, din linia de comandă (la numericele căutătoare NU se folosește ultima poziție de argv pentru asta, în plus sunt două variante, sunt a și b, b-ul fiind destinat situației când numele fișierului de rezultate trebuie de la bun început să aibă o literă sau o cifră în plus față de cel original, dacă acela original există deja), iar al doilea executabil, cel lansat automat, va căpăta litera b din lista de parametri transmiși la clauza aceea de system(), unde restul de parametri sunt identici cu cei inițiali scriși cu mâna în Guake. La numericele de mai sus, cum a și b sunt parametrii inițiali din Guake, la al doilea executabil, cel lansat automat, pe poziția parametrică ultimă vor fi c pe locul lui a și d pe locul lui b.

Și b pentru a la restul.

Și așa se lucrează mai ușor cu programele numerice când trebuiesc date date noi de căutare, dar atunci linia de comandă inițială trebuie îngrijită cu atenție, că de acolo se pornește.

***
Exemplu la NUMSIMPL (care caută numere noi înmulțind numere existente cu factori primi cu care nu se divid, sau împărțindu-le la primi cu care se divid o singură dată):

./numsimpl 180 200 /media/root/TB6/LIT200.LIT a 1 s 2 20000

unde avem așa:

* 180 și 200 sunt puteri de 10, cea inferioară și cea superioară.

* /media/root/TB6/LIT200.LIT este fișierul cu numere existente deja (nu GIG, pentru că în LIT-uri sunt stocate de preferință numerele deja noi obținute de la cel mai recent rând de căutări, din care numere se caută mai departe - numerele neproaspete din GIG-uri fiind astfel lăsate în pace ca să nu se caute de mai multe ori din aceleași numere și, așadar, pentru o mai bună viteză a căutării.
Fișierul are numere de la 181 la 200 de cifre, de asta 180 și 200 sunt limitele de interval din el în care se va căuta (în cazul de față tot fișierul), iar stabilirea limitelor (ca poziții de fseek în fișier) le face altă funcție auxiliară de tip URC (de la faptul de a urca printr-un fișier), apelată și ea dinlăuntrul lui NUMSIMPL.cc;

* a este litera a pomenită mai sus, dacă fișierul de căutare se vrea denumit exact așa cum este trecut în NUMSIMPL.cc, de pildă să presuppunem că este /media/root/TB10/VIEROIMER.NUM2 . Dacă numele ăsta este deja folosit, se trece la redenumiri, de la VIEROIMER2 în sus (și dincolo de cifra 9 vine A mare). La a doua lansare, în locul literei a vine c, sau în locul lui b vine d dacă VIEROIMER simplu este deja cu numerele.
Ca fișierele de rezultate din căutări separate să fie și ele tot separate unele de altele.

* 1 este prima cifră pe care trebuie să o aibă numerele cu numărul de cifre de unde se începe (egal cu 1 + primul parametru de după numele executabilului, căci numărul de cifre al unui număr este cu 1 peste puterea de 10 cea mai mare care este mai mică decât el ori maxim egală cu el).
Pentru că se face o verificare mai amănunțită a locului de unde trebuie pornit dintr-un fișier-depozit de numere, ca GIG140.TXT sau LIT120.LIT, de exemplu, și NU ajunge să știm câte cifre să aibă numerele de pornire, ci și cu ce cifră să înceapă ele (doar prima, în cazuri mai rare am căutat-o și pe a doua, care ocupă poziția Q[1] dacă numărul este trecut într-un vector char Q).
Prima cifră poate să fie și, de exemplu, 4, precum pe locul lui 180 poate să fie 182 (se pleacă de la numerele de 183 de cifre ce încep cu 4), și desigur că și pe locul lui 200 poate fi altceva, de pildă 190 de la jumătatea intervalului.

* s este direcția de căutare (în cazul de față în sus, numerele din LIT care NU se împart la factorii primi de legătură ce vor fi folosiți vor fi înmulțite cu ei). Dacă ar fi fost j, ar fi însemnat împărțire, când numerele din LIT depistate că se împart exact o dată la factorii aceia primi (în cazul de față nu la toți, pesemne, și ajungem curând și la ei) vor fi împărțite, pentru obținerea de noi numere);

* 2 și 20000 de la urmă sunt limitele, inferioară și superioară, pentru plaja de numere prime (factori de legătură) cu care se vor obține numerele unele din altele, prin înmulțire sau împărțire. Nu sunt toate numerele prime care există în mulțimea numerelor naturale până la 20000, ci doar o parte, bine definită la locul ei într-un vector, și ele provin din rândul numerelor prime care compun numerele multiperfecte și semiperfecte ale căror liste pot fi găsite pe Numericana.com, OEIS.org și pe „The Multiply Perfect Numbers Page” a lui Achim Flammenkamp (http://wwwhomes.uni-bielefeld.de/achim/mpn.html).

Sigur că de-a lungul timpului eu am mai adăugat niște numere prime, extrase de pildă cu ajutorul lui PARI/GP din puterile altor factori primi (scăzute cu 1), este o metodă de a obține factorizări prime pornind de la puterile altor prime. Dar experiența m-a învățat că primele componente ale acelor „multi” și „semi” sunt în continuare o bază bună pentru numere, fără nevoia imperioasă de a mai pune și alte prime.

Și vectorii de numere prime (componente pentru numere sau de legătură la căutări) sunt și ei de mărimi diferite în funcție de ce număr de cifre au numerele dorite, dar în general, la numerele de maxim 240 de cifre, sunt cel mult câteva sute (sub 700) de factori primi, care ajung și la peste 15 cifre cei mai mari.
Așa că în mod sigur nu pot fi toți cei posibili până la 20000, și sunt bine abordabili de-acolo din vectori, de deoparte.


******

Să dăm și un exemplu de program necăutător, recompilat automat, care are altfel lfăcută lista de parametri:

./ERMETE /run/media/root/14TB/GIG160.TXT a

Aici ermetele trebuie să declanșeze îmbogățirea unui mare depozit numeric (acel GIG160.TXT) cu cele mai noi numere de la 151 la 160 de cifre găsite la căutările recente, iar litera a de la capăt vrea să ne spună că așa se pornește manual programul. Se verifică dacă litera a apare la începutul ultimului parametru din argv și, dacă da, se apelează cu clauza system() un g++ de ERMETE, scris chiar în ERMETE.cc, apoi apelul de mai sus, cu ultima literă înlocuită cu b, este refăcut tot printr-o system() și imediat se iese cu exit() din primul ERMETE, ca să nu fie doi în memorie.

Aș fi putut pune în parametri și intervalele de căutare (150 și 160), dar în realitate intervalul poate să varieze chiar și în funcție de prima cifră a numărului de jos, ca la NUMSIMPL, și aici la ermeți nu am vrut îngreunarea asta.

Comentarii

Postări populare