La criba de Atkin es un algoritmo para encontrar todos los números primos hasta un número entero N dado. El algoritmo fue creado por A. O. L. Atkiny D. Yu. Bernstein[1] [2] . La velocidad asintótica del algoritmo declarada por los autorescorresponde a la velocidad de los mejores algoritmos de tamizado conocidos anteriormente, pero en comparación con ellos, el tamiz de Atkin requiere menos memoria.
La idea principal del algoritmo es utilizar formas cuadráticas irreducibles (representación de números como ax 2 + by 2 ). Los algoritmos anteriores eran básicamente diversas modificaciones de la criba de Eratóstenes , que utilizaba la representación de números en forma de formas reducidas (normalmente en forma de producto xy ).
De forma simplificada, el algoritmo se puede representar de la siguiente manera:
Para reducir los requisitos de memoria, el "tamizado" se realiza en porciones (segmentos, bloques), cuyo tamaño es de aproximadamente .
Para acelerar las cosas, el algoritmo ignora todos los números que son múltiplos de uno de los primeros números primos (2, 3, 5, 7, ...). Esto se hace utilizando estructuras de datos estándar y algoritmos de procesamiento de datos propuestos anteriormente por Paul Pritchard [3 ] . Se les conoce con el nombre en inglés. tamizado de ruedas . El número de primeros primos se elige en función del número dado N. Teóricamente, se propone llevar los primeros primos aproximadamente hasta . Esto nos permite mejorar la estimación asintótica de la velocidad del algoritmo por el factor . En este caso, se requiere memoria adicional que, a medida que crece N, se limita como . El aumento en los requisitos de memoria se estima en .
La versión presentada en el sitio web de uno de los autores [4] está optimizada para buscar todos los números primos hasta mil millones ( ), y los números que son múltiplos de 2, 3, 5 y 7 están excluidos de los cálculos (2 × 3 × 5 × 7 = 210).
Según los autores de [2] , el algoritmo tiene una complejidad asintótica y requiere bits de memoria. Anteriormente, se conocían algoritmos que eran igual de rápidos asintóticamente, pero que requerían mucha más memoria [5] [6] . En teoría, este algoritmo combina la velocidad máxima con los requisitos de memoria más bajos. La implementación del algoritmo, realizada por uno de los autores, muestra una velocidad práctica bastante alta [4] .
El algoritmo utiliza dos tipos de optimización, que aumentan significativamente su eficiencia (en comparación con la versión simplificada).
A continuación se muestra una implementación de una versión simplificada en el lenguaje de programación C , que ilustra la idea principal del algoritmo: el uso de formas cuadráticas:
límite int = 1000 ; int sqr_lim ; bool es_principal [ 1001 ]; int x2 , y2 ; int i , j ; intn ; _ // Inicialización del tamiz sqr_lim = ( int ) sqrt (( long double ) limit ); para ( i = 0 ; i <= límite ; ++ i ) es_primo [ i ] = falso ; es_primo [ 2 ] = verdadero ; es_primo [ 3 ] = verdadero ; // Presumiblemente, los primos son números enteros con un número impar // de representaciones en las formas cuadradas dadas. // x2 e y2 son i y j cuadrados (optimización). x2 = 0 ; para ( yo = 1 ; yo <= sqr_lim ; ++ yo ) { x2 += 2 * i - 1 ; y2 = 0 ; para ( j = 1 ; j <= sqr_lim ; ++ j ) { y2 += 2 * j - 1 ; n = 4 * x2 + y2 ; si (( n <= límite ) && ( n % 12 == 1 || n % 12 == 5 )) es_primo [ n ] = ! es_primo [ n ]; // n = 3 * x2 + y2; n- = x2 ; // Optimización si (( n <= límite ) && ( n % 12 == 7 )) es_primo [ n ] = ! es_primo [ n ]; // n = 3 * x2 - y2; n -= 2 * y2 ; // Optimización si (( i > j ) && ( n <= límite ) && ( n % 12 == 11 )) es_primo [ n ] = ! es_primo [ n ]; } } // Eliminar múltiplos de los cuadrados de números primos en el intervalo [5, sqrt(limit)]. // (el escenario principal no puede eliminarlos) for ( i = 5 ; i <= sqr_lim ; ++ i ) { si ( es_primo [ yo ]) { n = yo * yo ; para ( j = n ; j <= límite ; j += n ) es_primo [ j ] = falso ; } } // Imprime una lista de números primos en la consola. imprimirf ( "2, 3, 5" ); for ( i = 6 ; i <= limit ; ++ i ) { // Se ha añadido la comprobación de la divisibilidad entre 3 y 5. No es necesario en la versión original del algoritmo. if (( es_primo [ i ]) && ( i % 3 != 0 ) && ( i % 5 != 0 )) printf ( ", %d" , i ); }