En un post anterior escribí el código para encontrar números primos en Java. A diferencia del código en aquel post, aquí he usado una representación digital de la criba o coladera de Eratóstenes. Usar una representación en memoria tiene la ventaja de que nos permite ahorrarnos muchos cálculos innecesarios que el anterior código hacía para comprobar si un número era primo. Además, gracias a que cualquier compilador moderno nos permite declarar arreglos o reservar bloques de memoria de tamaño arbitrario, es posible usar este código para encontrar fácilmente los números primos por debajo de 1,000,000,000 (o cualquier número en el rango del tipo de datos int).
#include
#include
#include
#include
#define LIMITE 100000000
uint8_t *criba;
int contador = 0;
int main() {
criba = calloc(LIMITE, 1);
assert(criba);
for (int i = 2; i < LIMITE; i++) {
if (criba[i] == 0) {
contador++;
printf("%d\n", i);
uint64_t mul = i * 2;
while (mul < LIMITE) {
criba[mul] = 1;
mul += i;
}
}
}
printf("Se encontraron %d números primos menores a %d.\n", contador, LIMITE);
}
El código anterior define LIMITE con un valor de 100,000,000 y en mi PC toma aproximadamente 4 segundos al programa para encontrar los números primos por debajo de ese valor. Si incremento el valor de LIMITE a 1,000,000,000 toma aproximadamente 40 segundos en mi PC, que sigue siendo más rápido que el tiempo que tomaba la versión anterior del código para un valor de 100,000,000. Nota que puede llegar a millones la cantidad de números primos para estos valores de LIMITE, por lo que recomiendo enviar la salida del programa a un archivo y no directamente a la terminal. Es decir, ejecuta el programa de la siguiente manera:
monstruosoft@debian:~/code$ ./primos > /dev/shm/primos.txt
En el archivo primos.txt se guardará la salida del programa, por ejemplo:
2
3
5
7
11
13
17
19
23
29
31
37
...
999999667
999999677
999999733
999999739
999999751
999999757
999999761
999999797
999999883
999999893
999999929
999999937
Se encontraron 50847534 números primos menores a 1000000000.
Nota también que aunque este código puede fácilmente reservar un bloque de memoria de 1 GB en C, el mismo código en Java siempre me daba errores de OutOfMemoryException. Incluso después de aumentar el tamaño de la memoria usada por la máquina virtual de Java, usar System.out.println() era extremadamente lento para intentar escribir varios millones de líneas de texto a un archivo, y un ArrayList con varios millones de números primos también causaba problemas al intentar usar el método toString() así que si conoces la forma de usar este código en Java deja un comentario.