Nou plan de reformă la numere

Pentru Reforma Spiralei: înmulțire cu împărțire fără RandomLib, adică substituție rezonabilă de puteri de factori primi pentru numerele de fond 1 ca să fie obținute unele din altele. Fără nevoia masei mari auxiliare de manevră și fără câcâiala cu RandomLib, care poate fi repetitiv și învârtitor în jurul cozii (ex. VECUNSUB).

Pentru fiecare număr de fond 1 din N3.TXT, se fac numărătorul și numitorul abundențial, care se modifică apoi printr-o înmulțire și o împărțire cu doi factori distincți, corespunzători, din COEFLEG (pot fi și numere prime, nu doar compuse), în primă fază cu factori impari, pot fi și pari. Lucrurile se abordează gradual.

Dacă noul numitor abundențial de după cele două operații corespunde definiției (Numere naturale de maxim 1910 cifre, unde numitorul fracției ireductibile suma divizorilor/număr este maxim 10), atunci numărul nou obținut se înmagazinează.

Pot fi combinații diferite de abordare a înmulțirii și împărțirii: NUMSIMPL cu NUMSIMPL, NUMSIMPL cu MODPRIME, MODPRIME cu MODPRIME, NUMSIMPL cu MODPRIMSUM, MODPRIME cu MODPRIMSUM, MODPRIMSUM cu MODPRIMSUM.

Și, desigur, mai adăugăm aici elementul de combinație înmulțire/împărțire, în sensul că fiecare dintre cele șase situații de mai sus poate fi pusă pe înmulțire/împărțire sau invers, deci douăsprezece situații posibile în total, care, pentru eficiența programării, ar trebui separate. Ne amintim că în programare chiar se folosește un principiu numit „Separation of Principles”, în categoria SOLID.


Dar ce înseamnă NUMSIMPL, MODPRIME și MODPRIMSUM?


La NUMSIMPL, numărul deja existent în fondul 1 (cel cu numere din definiția aceea, fondul 2 fiind masa auxiliară de manevră, mult mai mare, unde numitorul abundențial era peste 10) se ia și se înmulțește sau se împarte cu un factor prim, cu următoarele condiții:

-se înmulțește o singură dată cu factorul prim (impar) dacă nu este divizibil cu el;

/se împarte cu factorul acela prim dacă este divizibil o singură dată cu el.


La MODPRIME, numărul de fond 1 se modifică tot printr-un singur factor prim, dar acoperind situațiile neacoperite la NUMSIMPL, adică:

-ori se înmulțește cu numărul prim, dacă este deja divizibil cu el;

-ori se împarte cu el, dacă este divizibil cu pătratul perfect al factorului (care este deja prestocat într-un vector de pătrate). Aici se preferă acele numere prime care, în numerele de fond 1, pot apărea la puterea a doua în factorizare, și care, în plaja de factori primi aferentă unei anumite game de număr de cifre ale numerelor, poartă numele de „cele H numere prime” - acelea cu potențial de multiputere. Ele sunt mai mici de 2 la puterea 32, deci pătratele lor sunt sub 2 la 64 și pot fi cu toatele (ele plus pătratele) tratate ca întregi fără semn pe 64 de biți, adică gmp_ui sau unsigned long long (tip nativ), nu mpz_t.


La MODPRIMSUM, avem factorii de legătură compuși (produse de puteri de factori primi, care puteri pot fi unitare sau multiple, ori chiar puteri simple de factori primi precum pătrate perfecte, cuburi perfecte..., oricum, factori compuși, de obicei impari, dar există și cazuri de paritate, tip MODPARSUM). MODPRIMSUM este cel mai complex caz de tratare numerică la modificarea abundenței numărului, iar factorii compuși sunt dezintegrați pe factorii primi componenți, care sunt tratați element cu element. Matricile de puteri prime de la reforma PUTERNUM (iarna 2017-2018) își au rostul lor peste tot, acea reformă trebuia neapărat făcută.


Reforma Spiralei presupune, pentru fiecare număr, o dublură de operații din suita de mai sus, combinabile. Este plauzibil ca foarte frecvent folosite să fie cele de MODPRIMSUM cu MODPRIMSUM, însă nu excludem combinabilele și, în general, pe celelalte (doar cu numere prime).

Astfel, se fac doi vectori separați de factori de legătură (unul pentru înmulțiri, altul pentru împărțiri), care au intervale de început și sfârșit (de pildă, între 100 și 500 factorii de sus, și între 50 și 300 cei de jos).

Se face o parcurgere de tip bidimensional, adică pentru fiecare element dintr-un vector se iau la rând ceilalți din celălalt vector, deci m*n perechi de numere (m elemente din primul ori n elemente din celălalt).

Elementele de legătură de la substituția de puteri de factori primi trebuie să respecte următoarele condiții:


-Să nu fie egale (nu are sens să obținem același număr);

-Dacă unul este divizibil cu celălalt, factorul mai mic este eliminat (redus), iar cel mare devine câtul împărțirii lor și se folosește numai el (doar înmulțire sau doar împărțire, depinde de care factor este multiplul cui). Nu are rost să înmulțești cu 625 și să împarți apoi la 25 sau invers, poți direct să înmulțești sau să împarți cu 25 și-atât (iar la împărțire, de verificat dacă numărul mare se divide cu împărțitorul), este mai ușor și la partea de MODPRIMSUM (se înțelege că aici vorbim doar despre factorii compuși de legătură, numerele prime oricum nu pot fi divizibile între ele, pot fi cel mult egale ca la punctul de mai sus);

-Tot la factorii compuși, se prea poate ca într-o pereche aceștia să nu fie primi între ei (pe când numerele prime sunt totdeauna prime între ele). De exemplu, 105 și 55. Să zicem că înmulțești cu 105 și împarți la 55. Este totuna cu a înmulți cu 21 și a împărți la 11, mai simplu și pentru MODPRIMSUM, pentru aceasta trebuie făcut preventiv un CMMDC natural între cei doi factori și extrase direct valorile ireductibile, și bineînțeles de verificat divizibilitatea numărului mare cu împărțitorul. Dacă nu este divizibil, putem trece mai departe.


Astfel, pentru simplificarea procesului de MODPRIMSUM, se pot face reduceri convenabile în perechile de numere prime. Iar acest lucru ar trebui aranjat o singură dată, la începutul programului, după ce au fost încărcați vectorii inițiali cu elemente de legătură, nu stresăm fiecare număr de fond 1 cu aranjamentele astea. Iar de la număr la număr, de la caz la caz, vor varia factorii cu care este divizibil. Și, evident, reducționismul acesta nu trebuie aplicat la căutările făcute exclusiv cu factori primi. Mai interesant este când un vector este cu primi și altul cu compuși, căci și acolo va trebui aplicat un reducționism pe perechi, iar în cazul în care într-o pereche un factor a fost redus la 1, cu MODPRIMSUM unitar sau amestecat cu celelalte, putem alege să trecem mai departe (pentru înmulțiri și împărțiri singulare există alți algoritmi). La Spirale, numerele se obțin neapărat unele din altele cu înmulțire ȘI împărțire, cu factori diferiți de 1.


Numerele de fond 1 se vor citi din fișier împreună cu numărătorul și numitorul lor abundențiale, ca termeni de fracțiie ireductibilă, iar în operațiile de NUMSIMPL, MODPRIME și MODPRIMSUM modificarea se va face direct asupra acelor doi termeni abundențiali (nu se va calcula de la zero o sumă nouă de divizori). În noiembrie 2019, înainte de pauza cea mare, pentru lucrul cu termenii abundențiali existau deja variante speciale: NNUMSIMPL, NMODPRIME și HMODPRIMSUM.


Iar funcțiile de prelucrare numerică din spate (de NUMSIMPL, MODPRIME și MODPRIMSUM) vor trebui și ele adaptate. În prezent, ele înglobează direct toată suita de numere de parcurs (în speță, pot fi și de fond 2) din fișierul de valori înmagazinate, și în funcție de direcția de căutare (sus, jos) și de plaja de număr de cifre se aleg anumite metode, care fac și citirea din fișier de la un cap la altul. În schimb, la Reforma Spiralei citirea din fișier va trebui cumva scoasă în afara metodei de modificare a abundenței, căci fiecare număr citit astfel va primi două astfel de metode succesive (una cu înmulțirea și alta cu împărțirea). Și scrierea în fișierul de rezultate a numărului final va fi făcută după terminarea ambelor prelucrări (acum, scrierea se face din interiorul metodei singulare de prelucrare: înmulire ori împărțire), deci și această scriere finală trebuie scoasă din zona de prelucrare numerică. Bine barem că există deja metodele de calcul. Dar trebuie pusă la punct partea cu fracțiile abundențiale de fond 1, să existe un fișier derivat din N3.TXT care, după fiecare număr, măcar din cele mai mari, să aibă numărătorul și numitorul abundențial, scrise pe rândurile următoare. De exemplu, după numărul 6 (primul număr perfect, cu suma divizorilor 12, deci 2 ori el) să apară 2 și 1, adică 2/1 sau 2 fracția abundențială; sau după 24, care are suma divizorilor 60, adică de 2.5 ori el însuși sau 5/2, să apară 5 și 2. Și cu 5 și cu 2 să lucrăm întru modificarea abundenței, fără a mai calcula alte sume integrale de divizori. Un proces destul de costisitor la mepezetelele mai mari, să stai să tot faci sume.


Desigur că mpz_t va fi tipul de date și pentru termenii abundențiali modificați, la numerele mari, în special pe la MODPRIMSUM aceștia pot varia suficient de mult încât să aibă valori de la 2 la puterea 64 în sus, și să fie nevoie și de niște CMMDC-uri de mpz_t; însă oricum este de așteptat ca valorile lor să fie semnificativ mai mici decât cele ale sumelor integrale de divizori, care, la rândul lor, aveau și așa nevoie la sfârșit de o operație de CMMDC între ele și numărul mare și-apoi un divexact pentru obținerea numitorului abundențial.


Poate că Reforma Spiralei va aduce rezultate de fond 1 în timp rezonabil, și fără povara spațiului imens (stocare mare și RAM mult) presupusă de folosirea numerelor auxiliare, care în fapt tot la niște substituții voalate de puteri prime duc - și care presupun foarte mult lucru specific, ca un maaare ocol, până să ajungem tot la noutățile eventuale de fond 1 dorite. Și fără repetitivitatea și monotonia în rezultate, pe care a arătat-o VECUNSUB (substituția aleatoare de puteri de factori primi) cu RandomLib (plus că acolo valorile de variație ale puterilor de factori primi pot fi cam disparate între ele, contrastante, mai mari sau mai mici, pe când la Spirală, cu intervale compacte de factori de legătură, nu neapărat numere mari, există mai mult control și mai multă compactitudine asupra valorilor folosite).


Bineînțeles că rămânem cu GMP ca bibliotecă de numere mari, dar mai scăpăm de nevoia de OMP și de RandomLib (multe programe secvențiale pot fi rulate concomitent pe threadurile procesoristice). Forța procesoristică rămâne o necesitate, și deocamdată plăcile video nu par să aibă un software la fel de bun pentru numerele naturale mari, așa cum este mpz_t de pe GMP pentru CPU-uri. Altfel, forța mult mai mare și mai rentabilă la preț a plăcilor video puternice (3080...) chiar ar merita, comparativ cu cea de CPU (fie și Threadripper). Și momentan nici nu suntem în postura să lucrăm remote cu un hardware cumplit de puternic în Cloud contra unei subscripții rezonabile de utilizator (una semnificativ mai ieftină, comparativ cu cât ar costa măgăoile hardware fizice din casă), așa că tot cu grămejoiul hardware din casă la putere, în special cu Threadripper.


FILTRARM este programul destinat să scrie numerele de fond 1 (sau 2) în fișiere cu valorile abundențiale.

Fișierele de căutare pentru Spirală vor trebui cumva derivate din actualele NNUMSIMPL, NMODPRIME și HMODPRIMSUM, cu doi vectori separați și, pentru MODPRIMSUM, și prelucrați dinamic pe perechi (înseamnă că vor fi generate valori noi, unele cu câte un 1 pe pereche, ceea ce invalidează perechea respectivă).


Să presupunem că avem 80 de valori între 300 și 500 și alte 60 între 700 și 900 (indiferent dacă una este de înmulțire și alta de împărțire, adică în sus și respectiv în jos).

Vor fi 80*60 de numere și deci 4800 de perechi de numere, disponibile pentru fiecare număr de fond 1 de care ne folosim la căutare.


Dar prin cele 4800 de perechi pot fi situații când (dacă intervalele se întrepătrund) să fie factori egali (invalid), unul să fie divizor al celuilalt (iarăși invalid, s-ar ajunge la o singură operație din două cerute, un factor devenind 1 sau element neutru la înmulțire ori împărțire), sau să nu fie primi între ei factorii (caz valid, dar trebuie făcută reducția prin CMMDC). Cum ziceam, filtrarea asta a perechilor de căutare trebuie făcută o dată și bine, dintru început de program, și ar putea chiar fi pusă într-un singur vector special (unde factorii să fie abordați doi câte doi).

Partea cu factorii doi câte doi ar putea fi aplicată și la numerele strict prime, decât să obosim memoria cu doi vectori, mai bine unul și bun. Și acolo unde un prim și un compus fac pereche, desigur. Cu respectarea regulilor de inegalitate, nedivizibilitate și ireductibilitate. Și din exemplul ipotetic cu 4800 de perechi de mai sus, foarte probabil nu toate vor fi viabile, în plus de la număr la număr vor fi cazuri când nu se va putea face împărțirea, deși perechea a fost găsită validă, și atunci se va omite de asemenea; omisiunea va fi făcută din start la pasul respectiv, astfel că numărul de bază nu va mai fi modificat și prelucrat deloc. Se va începe cu verificarea divizibilității sale cu împărțitorul ireductibil din pereche. Valabil și la numere prime, și la compuse. Dar sigur, cea mai complicată muncă va fi la MODPRIMSUM.


Mai întâi trebuie citit numărul de bază din fișier, apoi pornită parcurgerea perechilor. Iar și mai înainte, trebuiesc aranjate aceste perechi, să fie totul ireductibil și, de preferință, fără „unari” și desigur și fără „egale”.

Comentarii

Postări populare