Para números muy pequeños, digamos 32 bits sin signo, probar todos los divisores hasta la raíz cuadrada es un enfoque muy decente. Se pueden hacer algunas optimizaciones para evitar probar todos los divisores, pero estas mejoras son marginales. La complejidad sigue siendo $O(\sqrt n)$ .
Por otro lado, existen pruebas de primalidad mucho más rápidas, pero son bastante sofisticadas y despliegan su eficacia para números mucho más largos.
¿Existe una solución intermedia, es decir, un algoritmo relativamente sencillo, que sea de utilidad práctica para, digamos, 64 bits sin signo, con un tiempo de ejecución objetivo inferior a 1 ms?
No busco la microoptimización del método de división exhaustiva. Busco un principio de funcionamiento mejor, de una complejidad razonable (y de tipo determinista).
Actualización:
Utilizando una versión Python de la prueba Miller-Rabin del código Rosetta, el tiempo para el prime $2^{64}-59=18446744073709551557$ es $0.7$ ms. (Aunque esto no es una prueba suficiente porque nada dice que estemos en el peor de los casos).
http://rosettacode.org/wiki/Miller%E2%80%93Rabin_primality_test#Python:_Proved_correct_up_to_large_N
Y supongo que este código se puede mejorar para aumentar la velocidad.
0 votos
Puedes construir una criba filtrando los múltiplos de cualquier primo que ya hayas probado a medida que avanzas. Pero, por supuesto, necesitarás más memoria para realizar el seguimiento.
2 votos
@Zubzub: para un primo cercano a 2^64, la función intentará cerca de 2^32 divisiones, así que no. (Por cierto, para 18446744073709551557 tarda seis minutos).
2 votos
@mathreadler: Dudo que esto sea utilizable para enteros de 64 bits. Y si estoy en lo cierto, la ganancia no superará un factor log(n), sin contar los gastos generales.
0 votos
100 millones de divisiones en lugar de 2.000 millones es mejor, teniendo en cuenta que la división es lenta. Almacenar una tabla requiere menos de 20 megabytes si almacenamos la primalidad como bits.
0 votos
@mathreadler Tengo la sensación de que algoritmos como Miller-Rabin ya serán mucho más rápidos que la fuerza bruta para 64 bits, y por la pregunta, parece que incluso esos son demasiado lentos.
0 votos
Creo que bajar a 1 s debería ser factible con ese enfoque, pero 1ms, tienes razón... quizá no.
0 votos
Hay algunas afirmaciones en math.stackexchange.com/preguntas/2450722/ especialmente la sección de 64 bits. Quizás @DanaJ responda/comente, si no, puedes encontrar código C nativo en su página github.com/danaj/Math-Prime-Util . Ver también math.stackexchange.com/a/897442/61216
0 votos
Oye, ni siquiera necesitamos hacer una división para cada nuevo primo, también podemos hacer un bucle de "contar hacia arriba, acumular y encontrar el mínimo". Eso sería mucho mejor para las tuberías de la CPU y daría latencias mucho más bajas.
0 votos
Existen instrucciones SIMD realmente eficientes para encontrar $\displaystyle\min_{i}|a-b_i|$ durante unas 8 o 16 expresiones de este tipo por ciclo.
1 votos
$1$ segundo es absolutamente ningún proeblema. Incluso $100$ -con PARI/GP mediante la prueba de Adleman-Pomerance-Rumely en un plazo aproximado de $200$ milisegundos. Pero $1ms$ ? Quizás sea buena idea la prueba BPSW, que es correcta hasta al menos $2^{64}$ . La división de prueba sólo tiene sentido, si queremos probar muchos números, para reducir el número de candidatos, pero verificando $64$ -números de bits a través de la división de prueba en realidad no es eficiente. Pero comprobar los primeros números primos (digamos hasta $100$ ) podría mejorar ligeramente la prueba.
0 votos
Probé un $20$ -y aplicamos la prueba de Adleman-Pomernace-Rumely con PARI/GP. El temporizador muestra " $0$ ", por lo que parece tardar menos de un milisegundo.
0 votos
Le sugiero que mueva su Actualización a una respuesta.
0 votos
@lhf: quizá más adelante, si veo que es posible optimizarlo. En cualquier caso me quedo con la respuesta aceptada.
1 votos
Una aplicación determinista con un máximo de
7
pruebas de base, aquí .