Este es el mejor algoritmo que pude encontrar.
def get_primes(n):
numbers = set(range(n, 1, -1))
primes = []
while numbers:
p = numbers.pop()
primes.append(p)
numbers.difference_update(set(range(p*2, n+1, p)))
return primes
>>> timeit.Timer(stmt='get_primes.get_primes(1000000)', setup='import get_primes').timeit(1)
1.1499958793645562
¿Se puede hacer aún más rápido?
Este código tiene una falla: dado que numbers
es un conjunto desordenado, no hay garantía de que numbers.pop()
elimine el número más bajo del conjunto. Sin embargo, funciona (al menos para mí) para algunos números de entrada:
>>> sum(get_primes(2000000))
142913828922L
#That's the correct sum of all numbers below 2 million
>>> 529 in get_primes(1000)
False
>>> 529 in get_primes(530)
True
python
math
optimization
primes
jbochi
fuente
fuente
import antigravity
. ¿No hay nada comorequire 'prime'; Prime.take(10)
(Ruby)?Respuestas:
Advertencia: los
timeit
resultados pueden variar debido a diferencias en el hardware o la versión de Python.A continuación hay un script que compara varias implementaciones:
Muchas gracias a stephan por llamar mi atención sobre sieve_wheel_30. El crédito es para Robert William Hanks por primesfrom2to, primesfrom3to, rwh_primes, rwh_primes1 y rwh_primes2.
De los métodos Python simples probados, con psyco , para n = 1000000, rwh_primes1 fue el más rápido probado.
De los métodos Python simples probados, sin psyco , para n = 1000000, rwh_primes2 fue el más rápido.
De todos los métodos probados, permitiendo numpy , para n = 1000000, primesfrom2to fue el más rápido probado.
Los tiempos se midieron con el comando:
con
{method}
reemplazado por cada uno de los nombres de método.primes.py:
La ejecución del script prueba que todas las implementaciones dan el mismo resultado.
fuente
gmpy
: tiene un soporte bastante bueno para los primos, a través delnext_prime
método de sumpz
tipo.Código Python puro más rápido y con más memoria:
o comenzando con medio tamiz
Código numpy más rápido y con más memoria:
Una variación más rápida que comienza con un tercio de un tamiz:
Una versión de Python puro (difícil de codificar) del código anterior sería:
Desafortunadamente, pure-python no adopta la forma más simple y rápida de hacer asignaciones, y llamar
len()
dentro del bucle como en[False]*len(sieve[((k*k)//3)::2*k])
es demasiado lento. Así que tuve que improvisar para corregir la entrada (y evitar más matemáticas) y hacer un poco de magia matemática extrema (y dolorosa).Personalmente, creo que es una lástima que numpy (que es tan ampliamente utilizado) no forme parte de la biblioteca estándar de Python, y que las mejoras en la sintaxis y la velocidad parecen ser completamente ignoradas por los desarrolladores de Python.
fuente
bitarray
, como se usa aquí (para el tamiz primario más simple; ¡no un contendiente en la carrera aquí!) stackoverflow.com/questions/31120986/…primesfrom2to()
método, ¿la división debe estar dentro de los corchetes?Hay una muestra bastante ordenado del libro de cocina de Python aquí - la versión más rápida propuesta en esa dirección URL es:
eso daría
Midiendo en el indicador de comandos de shell (como prefiero hacer) con este código en pri.py, observo:
entonces parece que la solución de Cookbook es más del doble de rápido.
fuente
Usando Sundaram's Sieve , creo que rompí el récord de Python puro:
Comparación:
fuente
None
lugar de la función original funciona y es aún más rápido quezero.__sub__
sundaram3(9)
volverá[2, 3, 5, 7, 9]
? Parece hacer esto con numerosos, tal vez todos, números impares (incluso cuando no son primos)El algoritmo es rápido, pero tiene una falla grave:
Asume que eso
numbers.pop()
devolvería el número más pequeño del conjunto, pero esto no está garantizado en absoluto. Los conjuntos no están ordenados ypop()
eliminan y devuelven un elemento arbitrario , por lo que no se puede usar para seleccionar el próximo primo de los números restantes.fuente
Para una solución verdaderamente más rápida con N suficientemente grande sería descargar una lista precalculada de números primos , almacenarla como una tupla y hacer algo como:
Si
N > primes[-1]
sólo se calculará entonces más números primos y guardar la nueva lista en su código, así que la próxima vez que es igual de rápido.Siempre piensa fuera de la caja.
fuente
Si no desea reinventar la rueda, puede instalar la biblioteca simbólica de matemáticas simulada (sí, es compatible con Python 3)
Y usa la función de primer rango
fuente
Si acepta itertools pero no numpy, aquí hay una adaptación de rwh_primes2 para Python 3 que se ejecuta aproximadamente el doble de rápido en mi máquina. El único cambio sustancial es usar un bytearray en lugar de una lista para el booleano, y usar comprimir en lugar de una comprensión de lista para construir la lista final. (Añadiría esto como un comentario como moarningsun si pudiera).
Comparaciones:
y
fuente
Es instructivo escribir su propio código de búsqueda principal, pero también es útil tener a mano una biblioteca rápida y confiable. Escribí un contenedor alrededor de la biblioteca C ++ primesieve , lo llamé primesieve-python
Intentalo
pip install primesieve
Me daría curiosidad ver la velocidad comparada.
fuente
count_primes
función es mucho más rápida quegenerate_primes
Aquí hay dos versiones actualizadas (Python 3.6 puro) de una de las funciones más rápidas,
fuente
Una implementación determinista de la prueba de Primalidad de Miller-Rabin en el supuesto de que N <9.080.191
Según el artículo en Wikipedia ( http://en.wikipedia.org/wiki/Miller–Rabin_primality_test ) probando N <9.080.191 para a = 2,3,37, y 73 es suficiente para decidir si N es compuesto o no.
Y adapté el código fuente de la implementación probabilística de la prueba original de Miller-Rabin que se encuentra aquí: http://en.literateprograms.org/Miller-Rabin_primality_test_(Python)
fuente
Si tiene control sobre N, la forma más rápida de enumerar todos los números primos es calcularlos previamente. Seriamente. La precomputación es una optimización que se pasa por alto.
fuente
Aquí está el código que normalmente uso para generar primos en Python:
No puede competir con las soluciones más rápidas publicadas aquí, pero al menos es puro Python.
Gracias por publicar esta pregunta. Realmente aprendí mucho hoy.
fuente
Para el código más rápido, la solución más complicada es la mejor. Sin embargo, por razones puramente académicas, estoy publicando mi versión de Python pura, que es un poco menos del 50% más rápida que la versión del libro de cocina publicada anteriormente. Como hago la lista completa en la memoria, necesitas suficiente espacio para guardar todo, pero parece escalar bastante bien.
Y los resultados:
fuente
Una implementación ligeramente diferente de un medio tamiz usando Numpy:
http://rebrained.com/?p=458
¿Alguien puede comparar esto con los otros tiempos? En mi máquina parece bastante comparable al otro medio tamiz de Numpy.
fuente
upto=10**6
:primesfrom2to()
- 7 ms;prime6()
- 12 ms ideone.com/oDg2YTodo está escrito y probado. Por lo tanto, no hay necesidad de reinventar la rueda.
nos da un récord de 12,2 ms !
Si esto no es lo suficientemente rápido, puede probar PyPy:
lo que resulta en:
La respuesta con 247 votos positivos es de 15.9 ms para la mejor solución. Compara esto !!!
fuente
Probé algunas funciones de unutbu, lo calculé con un número de millones hambrientos
Los ganadores son las funciones que usan la biblioteca numpy,
Nota : También sería interesante hacer una prueba de utilización de memoria :)
Código de muestra
Código completo en mi repositorio github
fuente
Para Python 3
fuente
Tamiz primario más rápido en Pure Python :
Optimicé Sieve of Eratosthenes para velocidad y memoria.
Punto de referencia
Salida
fuente
La primera vez que uso Python, por lo que algunos de los métodos que uso en esto pueden parecer un poco engorrosos. Acabo de convertir directamente mi código de C ++ a Python y esto es lo que tengo (aunque un poco lento en Python)
fuente
Sé que la competencia está cerrada por algunos años. ...
Sin embargo, esta es mi sugerencia para un tamiz de Python Prime puro, basado en omitir los múltiplos de 2, 3 y 5 mediante el uso de los pasos apropiados mientras se procesa el tamiz hacia adelante. Sin embargo, en realidad es más lento para N <10 ^ 9 que las soluciones superiores de @Robert William Hanks rwh_primes2 y rwh_primes1. Al usar una matriz de tamices ctypes.c_ushort por encima de 1.5 * 10 ^ 8, de alguna manera se adapta a los límites de memoria.
10 ^ 6
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000)" 10 bucles, lo mejor de 3: 46.7 ms por bucle
10 ^ 7
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (10000000)" 10 bucles, lo mejor de 3: 530 ms por bucle
10 ^ 8
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (100000000)" 10 bucles, lo mejor de 3: 5.55 segundos por bucle
10 ^ 9
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000000)" 10 bucles, lo mejor de 3: 61,2 segundos por bucle
Puede copiar el siguiente código en ubuntus primeSieveSpeedComp para revisar estas pruebas.
fuente
Aquí hay una versión numpy de Sieve of Eratosthenes que tiene una buena complejidad (inferior a la clasificación de una matriz de longitud n) y vectorización. En comparación con @unutbu veces esto es tan rápido como los paquetes con 46 microsecons para encontrar todos los números primos por debajo de un millón.
Tiempos:
fuente
He actualizado gran parte del código para Python 3 y lo lancé a perfplot (un proyecto mío) para ver cuál es realmente el más rápido. Resulta que, para los grandes
n
,primesfrom{2,3}to
toma el pastel:Código para reproducir la trama:
fuente
Supongo que la forma más rápida es codificar los números primos en su código.
Entonces, ¿por qué no simplemente escribir un script lento que genera otro archivo fuente que tiene todos los números integrados y luego importar ese archivo fuente cuando ejecuta su programa real?
Por supuesto, esto funciona solo si conoce el límite superior de N en el momento de la compilación, pero este es el caso para (casi) todos los problemas del proyecto Euler.
PD: Podría estar equivocado si, en primer lugar, si analizar la fuente con primos cableados es más lento que calcularlos, pero hasta donde sé, Python se ejecuta desde
.pyc
archivos compilados , por lo que leer una matriz binaria con todos los primos hasta N debería ser sangriento rápido en ese caso.fuente
Disculpe la molestia, pero erat2 () tiene una falla grave en el algoritmo.
Mientras buscamos el próximo compuesto, solo necesitamos probar números impares. q, p ambos son impares; entonces q + p es par y no necesita ser probado, pero q + 2 * p siempre es impar. Esto elimina la prueba "if even" en la condición del bucle while y ahorra aproximadamente el 30% del tiempo de ejecución.
Mientras estamos en eso: en lugar del elegante método 'obtener y eliminar' D.pop (q, Ninguno) ', use' if q en D: p = D [q], del D [q] ', que es el doble de rápido ! Al menos en mi máquina (P3-1Ghz). Así que sugiero esta implementación de este algoritmo inteligente:
fuente
El método más rápido que he probado hasta ahora se basa en la función de libro de cocina Python
erat2
:Consulte esta respuesta para obtener una explicación de la aceleración.
fuente
Puede que llegue tarde a la fiesta, pero tendré que agregar mi propio código para esto. Utiliza aproximadamente n / 2 en el espacio porque no necesitamos almacenar números pares y también utilizo el módulo bitarray python, lo que reduce drásticamente el consumo de memoria y permite calcular todos los números primos hasta 1,000,000,000
Esto se ejecutó en un 64 OS 2.4GHZ MAC OSX 10.8.3
fuente
Recolecté varios tamices de números primos con el tiempo. Lo más rápido en mi computadora es esto:
fuente
Estoy respondiendo lentamente a esta pregunta, pero me pareció un ejercicio divertido. Estoy usando numpy que podría estar haciendo trampa y dudo que este método sea el más rápido, pero debería estar claro. Tamiza una matriz booleana que se refiere solo a sus índices y obtiene números primos de los índices de todos los valores verdaderos. No se necesita módulo.
fuente
ajs_primes3a(10)
->array([2, 3, 5, 7, 9])
.9
no es primordialnumpy
solución más lenta entre las que devuelve una matriz. Nota: ninguna implementación real de Sieve of Eratosthenes usa módulo, no es necesario mencionarlo. Podrías usar enmat[idx*idx::idx]
lugar demat[idx*2::idx]
. Ynp.nonzero(mat)[0]
en lugar denp.where(mat == True)[0]
.Aquí hay una técnica interesante para generar números primos (pero no la más eficiente) usando las comprensiones de la lista de Python:
Puedes encontrar el ejemplo y algunas explicaciones aquí
fuente