Búsqueda paralela de números primos
"Sieve for Seven", Scot Nelson. |
Existen varios algoritmos para obtener listas de números primos, tal vez el más común sea la criba de Eratóstenes, que consiste en escribir una lista con todos los números que queremos estudiar y, partiendo del primero, tachar todos sus múltiplos, y repetir el proceso cada vez con el primer número que no hayamos tachado.
Este algoritmo presenta dos problemas:
- Es destructivo (consiste en descartar), por lo que a priori consume demasiada memoria, y mucho tiempo en escribir candidatos.
- Eliminar objetos de una lista impide trabajar con ella desde otra hebra, ni siquiera para iterar, con lo que perdemos la posibilidad de trabajar con multinúcleo.
Esta técnica nos proporciona dos ventajas:
- La única modificación que haremos a la lista será añadir al final, de forma que en lugar de una lista podríamos utilizar un vector, cuyo acceso es mucho más rápido.
- Es posible paralelizar, porque podemos conseguir que los posibles divisores de cada candidato pertenezcan al vector que ya tenemos.
Todos los nuevos candidatos se reparten entre distintos procesos, que mantendrán el vector anterior como sólo lectura. Cada proceso tendrá un vector propio para guardar los número primos que encuentre, y al final de la etapa, todos ellos se añadirán al vector principal.
Esta gráfica muestra la mejora de tiempo que hemos conseguido con esta modificación de la criba de Eratóstenes:
Gráfica realizada con LibreOffice Calc. |
En el siguiente enlace se puede descargar el algoritmo de la criba de Eratóstenes (eratosthenes), la versión constructiva paralelizable (list) y una utilidad derivada para consultar si un número es primo (primeq). Está programada en C++ con OpenMP y viene compilada para Windows x64 y Linux x64, acompañada del código fuente:
$ ./list 2000000000Y ha encontrado 98.222.287 números primos en 8:48 minutos, un tiempo aceptable, con una ganancia de 3,5 sobre la versión secuencial (
./list -seq
), generando un archivo de 1GB con todos ellos. En un sobremesa con un Core i7 más moderno ha tardado 4:20 minutos. ¡Reto superado!
Comentarios
Publicar un comentario