Atkinin seula on algoritmi, joka etsii kaikki alkuluvut tiettyyn kokonaislukuun N asti. Algoritmin on luonut A. O. L. Atkinja D. Yu. Bernstein[1] [2] . Kirjoittajien ilmoittama algoritmin asymptoottinen nopeus vastaa tunnetuimpien seulontaalgoritmien nopeutta, mutta niihin verrattuna Atkin-seula vaatii vähemmän muistia.
Algoritmin pääideana on käyttää redusoitumattomia neliömuotoja (lukujen esitys ax 2 + x 2 :lla ). Aiemmat algoritmit olivat pohjimmiltaan erilaisia Eratosthenesin seulan muunnelmia , joissa käytettiin lukujen esittämistä pelkistetyissä muodoissa (yleensä tuotteen xy muodossa ).
Yksinkertaistetussa muodossa algoritmi voidaan esittää seuraavasti:
Muistivaatimusten vähentämiseksi "seulonta" suoritetaan osissa (segmenteissä, lohkoissa), joiden koko on noin .
Asian nopeuttamiseksi algoritmi jättää huomioimatta kaikki luvut, jotka ovat muutaman ensimmäisen alkuluvun (2, 3, 5, 7, ...) kerrannaisia. Tämä tehdään käyttämällä vakiotietorakenteita ja tietojenkäsittelyalgoritmeja, joita Paul Pritchard on aiemmin ehdottanut [3 ] . Ne tunnetaan englanninkielisellä nimellä. pyörän seulonta . Ensimmäisten alkulukujen lukumäärä valitaan annetun luvun N mukaan. Teoreettisesti ehdotetaan, että ensimmäiset alkuluvut otetaan suunnilleen arvoon . Näin voimme parantaa algoritmin nopeuden asymptoottista arviota kertoimella . Tässä tapauksessa tarvitaan lisämuistia, joka N:n kasvaessa rajoittuu muotoon . Muistitarpeen kasvun arvioidaan olevan .
Yhden kirjoittajan verkkosivustolla [4] esitetty versio on optimoitu etsimään kaikkia alkulukuja miljardiin asti ( ), ja luvut, jotka ovat 2:n, 3:n, 5:n ja 7:n kerrannaisia, on jätetty pois laskelmista (2 × 3 × 5 × 7 = 210).
[2] : n tekijöiden mukaan algoritmilla on asymptoottinen monimutkaisuus ja se vaatii bittejä muistia. Aikaisemmin tunnettiin algoritmeja, jotka olivat yhtä asymptoottisesti nopeita, mutta vaativat huomattavasti enemmän muistia [5] [6] . Teoriassa tämä algoritmi yhdistää suurimman nopeuden alhaisimpiin muistivaatimuksiin. Algoritmin toteutus, jonka yksi kirjoittajista on suorittanut, osoittaa melko suurta käytännön nopeutta [4] .
Algoritmi käyttää kahden tyyppistä optimointia, mikä lisää merkittävästi sen tehokkuutta (verrattuna yksinkertaistettuun versioon).
Alla on yksinkertaistetun version toteutus C -ohjelmointikielellä , joka havainnollistaa algoritmin pääideaa - neliömuotojen käyttöä:
int limit = 1000 ; int sqr_lim ; bool on alkuluku [ 1001 ]; int x2 , y2 ; int i , j ; int n ; // Seulan alustus sqr_lim = ( int ) sqrt (( long double ) limit ); for ( i = 0 ; i <= raja ; ++ i ) on_alkuluku [ i ] = epätosi ; on_alkuluku [ 2 ] = tosi ; on_alkuluku [ 3 ] = tosi ; // Oletettavasti alkuluvut ovat kokonaislukuja, joissa on pariton määrä // esityksiä annetuissa neliömuodoissa. // x2 ja y2 ovat i- ja j-neliöitä (optimointi). x2 = 0 ; for ( i = 1 ; i <= sqr_lim ; ++ i ) { x2 += 2 * i - 1 ; y2 = 0 ; for ( j = 1 ; j <= sqr_lim ; ++ j ) { y2 += 2 * j - 1 ; n = 4 * x2 + y2 ; if (( n <= raja ) && ( n % 12 == 1 || n % 12 == 5 )) on_alkuluku [ n ] = ! on alkuluku [ n ]; // n = 3 * x2 + y2; n = x2 ; // Optimointi jos (( n <= raja ) && ( n % 12 == 7 )) on_alkuluku [ n ] = ! on alkuluku [ n ]; // n = 3 * x2 - y2; n = 2 * y2 ; // Optimointi if (( i > j ) && ( n <= raja ) && ( n % 12 == 11 )) on_alkuluku [ n ] = ! on alkuluku [ n ]; } } // Karsitaan alkulukujen neliöiden kerrannaiset väliltä [5, sqrt(limit)]. // (päävaihe ei voi karsia niitä pois) for ( i = 5 ; i <= sqr_lim ; ++ i ) { if ( on_alkuluku [ i ]) { n = i * i ; for ( j = n ; j <= raja ; j += n ) on_alkuluku [ j ] = epätosi ; } } // Tulosta alkulukuluettelo konsoliin. printf ( "2, 3, 5" ); for ( i = 6 ; i <= limit ; ++ i ) { // jaotettavuus 3:lla ja 5:llä on lisätty. Algoritmin alkuperäisessä versiossa sitä ei tarvita. if (( on_alkuluku [ i ]) && ( i % 3 != 0 ) && ( i % 5 != 0 )) printf ( ", %d" , i ); }