¿Existe un algoritmo eficiente para encontrar el primo más pequeño mayor que N?

Creo que el enfoque más directo es implementar la prueba de Miller Rabin y luego intentar números consecutivos hasta encontrar un número primo. El número de candidatos que debe probar antes de encontrar un primo es proporcional al número de dígitos en el número con el que comienza (según el teorema del número primo), por lo que no tendrá que esperar mucho. Dependiendo de su perspectiva filosófica, podría molestarle que se trate de un algoritmo aleatorio, pero a efectos prácticos funciona muy bien.

Miller-Rabin es bastante fácil de implementar desde cero, y es casi seguro que sea lo suficientemente eficiente para sus propósitos. Aquí hay un ejemplo de implementación rápida y sucia en Python.

importar al azar

# Determina si a es testigo de Miller-Rabin de n
def is_witness (a, n):
q = n-1
k = 0
mientras q% 2 == 0:
q / = 2
k + = 1
b = pow (a, q, n)
si b == 1: devuelve False
para i en xrange (k):
si b == n-1: devuelve False
b = b * b% n
volver verdadero

# Prueba de Miller-Rabin, con 100 ensayos por defecto
def is_prime (n, ensayos = 100):
para i en xrange (ensayos):
a = random.randrange (1, n)
if is_witness (a, n): devuelve False
volver verdadero

def next_prime (n):
mientras que no (is_prime (n)): n + = 1
volver n

En mi máquina, esto puede decirme el primer primo después de [matemáticas] 10 ^ {100} [/ matemáticas] en menos de un segundo (es [matemáticas] 10 ^ {100} +267 [/ matemáticas], si usted es curioso). Hay muchas maneras de hacer que esto sea más eficiente, por supuesto (por ejemplo: no hay necesidad de probar números pares; 100 intentos es mucho más de lo que necesita estar seguro de que un número es primo; un lenguaje compilado sería más rápido).

Un lugar al que puede ir para leer sobre buenos algoritmos para esto es la documentación de Sage. Sage tiene una función incorporada “next_prime” que bien podría usar más métodos de vanguardia de los que he descrito. No estoy seguro de qué método utiliza.

El método más eficiente diferirá en función del tamaño de entrada, así como de los recursos y otras funciones que tenga disponibles. Estas son algunas de las formas más rápidas que conozco.

  1. Para entradas pequeñas, busque la respuesta en una tabla. Ridículamente rápido, pero muy limitado.
  2. Para entradas ligeramente más grandes, si tiene algunos datos tamizados, puede buscar rápidamente la respuesta. No es raro que muchos programas de teoría de números tengan un tamiz en caché para un rango pequeño. Por ejemplo, 334 bytes de memoria pueden darle una respuesta rápida para todas las entradas de menos de 10,000. 4k de memoria te llevan a ~ 120,000.
  3. Implemente pruebas rápidas de primalidad. Bucle en una primitiva de prueba de rueda mod-2, mod-6, mod-30 o mod-210. La velocidad promedio en una Macbook es inferior a 1 microsegundo para entradas de 32 bits, aproximadamente 3 microsegundos para 64 bits para Perl / teoría, aproximadamente 3 veces esas veces para Pari / GP. Ambos usan este método con una rueda mod-30 y mod-210 respectivamente. Ambos usan una prueba BPSW, por lo que los resultados de 64 bits son deterministas (no “primos probables”).
  4. Una vez en bigints, puedes mejorar la rueda siguiendo un mod 23 nativo de 32 bits. y hacer pruebas de divisibilidad simples con eso antes de llamar a la prueba de primalidad de números grandes.
  5. En algún lugar en el rango de 120 bits, es más rápido hacer un tamizado parcial. El lugar donde se encuentra este crossover depende del rendimiento de sus pruebas de primalidad y su código de tamizado. En este punto, es más rápido usar un tamiz en una ventana de tamaño razonable para eliminar compuestos suaves que reducen el número de pruebas de primalidad que tiene que ejecutar. Querrá ajustar la profundidad del tamiz (fundamental para el rendimiento) y el ancho del tamiz (tiene poco efecto si está dentro de límites razonables, como 5 a 60 méritos; utilizo 30). Tenga en cuenta que es posible que el próximo prime se encuentre fuera de su ventana, por lo que tendrá que resistir. Establecer el ancho en más de 30 méritos hace que sea una ocurrencia muy rara.

Debería poder encontrar más información sobre las pruebas rápidas de primalidad en otras preguntas. Estos métodos son mucho más rápidos que usar un tamiz completo y casi no requieren memoria. Sin embargo, si su objetivo es generar muchos primos sucesivos, entonces el tamizado (total o parcial según el tamaño de entrada) es la respuesta correcta. Para la mayoría de las personas, el elemento 3 será todo lo que usarán; el resto son optimizaciones para las personas que ejecutan esta función literalmente miles de millones de veces al día.

Creo que el Tamiz de Eratóstenes – Wikipedia implementado como generador sería lo mejor que puedes hacer. Me interesaría saber acerca de un algoritmo más eficiente que ese.