C'est le meilleur algorithme que j'ai pu trouver.
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
Peut-il être rendu encore plus rapide?
Ce code a un défaut: puisqu'il numbers
s'agit d'un ensemble non ordonné, il n'y a aucune garantie qui numbers.pop()
supprimera le numéro le plus bas de l'ensemble. Néanmoins, cela fonctionne (au moins pour moi) pour certains numéros d'entrée:
>>> 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
la source
la source
import antigravity
. N'y a-t-il rien commerequire 'prime'; Prime.take(10)
(Ruby)?Réponses:
Attention:
timeit
résultats peuvent varier en raison de différences de matériel ou de version de Python.Voici un script qui compare un certain nombre d'implémentations:
Un grand merci à stephan d' avoir porté sieve_wheel_30 à mon attention. Le mérite revient à Robert William Hanks pour primesfrom2to, primesfrom3to, rwh_primes, rwh_primes1 et rwh_primes2.
Parmi les méthodes Python simples testées, avec psyco , pour n = 1000000, rwh_primes1 a été la plus rapide testée.
Parmi les méthodes Python simples testées, sans psyco , pour n = 1000000, rwh_primes2 était la plus rapide.
De toutes les méthodes testées, permettant numpy , pour n = 1000000, primesfrom2to a été la plus rapide testée.
Les délais ont été mesurés à l'aide de la commande:
avec
{method}
remplacé par chacun des noms de méthode.primes.py:
L'exécution du script teste que toutes les implémentations donnent le même résultat.
la source
gmpy
- il a un assez bon support pour les nombres premiers, via lanext_prime
méthode de sonmpz
type.Code Python pur plus rapide et plus mémoire:
ou en commençant par un demi-tamis
Code numpy plus rapide et plus efficace en mémoire:
une variation plus rapide à partir d'un tiers de tamis:
Une version (difficile à coder) en python pur du code ci-dessus serait:
Malheureusement, pure-python n'adopte pas la méthode numpy plus simple et plus rapide pour effectuer l'affectation, et appeler
len()
à l'intérieur de la boucle comme dans[False]*len(sieve[((k*k)//3)::2*k])
est trop lent. J'ai donc dû improviser pour corriger les entrées (et éviter plus de mathématiques) et faire de la magie mathématique extrême (et douloureuse).Personnellement, je pense que c'est dommage que numpy (qui est si largement utilisé) ne fasse pas partie de la bibliothèque standard Python, et que les améliorations de la syntaxe et de la vitesse semblent être complètement ignorées par les développeurs Python.
la source
bitarray
- tel qu'utilisé ici (pour le tamis principal le plus simple; pas un concurrent dans la course ici!) stackoverflow.com/questions/31120986/…primesfrom2to()
méthode, la division doit-elle être à l'intérieur des supports?Il y a un échantillon assez soigné du livre de recettes Python ici - la version la plus rapide proposée sur cette URL est:
ce qui donnerait
Mesurant à l'invite du shell (comme je préfère le faire) avec ce code dans pri.py, j'observe:
il semble donc que la solution Cookbook soit deux fois plus rapide.
la source
En utilisant Sieve de Sundaram , je pense avoir battu le record de Python pur:
Comparaison:
la source
None
place de la fonction d'origine fonctionne et c'est encore plus rapide quezero.__sub__
sundaram3(9)
il reviendra[2, 3, 5, 7, 9]
? Il semble faire cela avec de nombreux - peut - être tous - nombres impairs (même quand ils ne sont pas premiers)L'algorithme est rapide, mais il a un sérieux défaut:
Vous supposez que
numbers.pop()
cela retournerait le plus petit nombre de l'ensemble, mais ce n'est pas du tout garanti. Les ensembles ne sont pas ordonnés etpop()
supprime et renvoie un élément arbitraire , il ne peut donc pas être utilisé pour sélectionner le premier nombre parmi les nombres restants.la source
Pour une solution vraiment plus rapide avec un N suffisamment grand serait de télécharger une liste pré-calculée de nombres premiers , de la stocker en tant que tuple et de faire quelque chose comme:
Si
N > primes[-1]
seulement alors calculez plus de nombres premiers et enregistrez la nouvelle liste dans votre code, la prochaine fois, c'est aussi rapide.Sortez toujours des sentiers battus.
la source
Si vous ne voulez pas réinventer la roue, vous pouvez installer la bibliothèque symbolique de mathématiques sympy (oui c'est compatible Python 3)
Et utilisez la fonction primerange
la source
Si vous acceptez itertools mais pas numpy, voici une adaptation de rwh_primes2 pour Python 3 qui tourne environ deux fois plus vite sur ma machine. Le seul changement substantiel consiste à utiliser un bytearray au lieu d'une liste pour le booléen, et à utiliser compress au lieu d'une compréhension de liste pour construire la liste finale. (J'ajouterais ceci comme un commentaire comme moarningsun si je pouvais.)
Comparaisons:
et
la source
Il est instructif d'écrire votre propre code de recherche principal, mais il est également utile d'avoir une bibliothèque rapide et fiable à portée de main. J'ai écrit un wrapper autour de la bibliothèque C ++ primesieve , je l' ai nommé primesieve-python
Essayez-le
pip install primesieve
Je serais curieux de voir la vitesse comparée.
la source
count_primes
fonction est beaucoup plus rapide quegenerate_primes
Voici deux versions mises à jour (Python 3.6 pur) d'une des fonctions les plus rapides,
la source
Une mise en œuvre déterministe du test de primalité de Miller-Rabin sur l'hypothèse que N <9 080 191
Selon l'article sur Wikipedia ( http://en.wikipedia.org/wiki/Miller–Rabin_primality_test ), tester N <9 080 191 pour a = 2,3,37, et 73 est suffisant pour décider si N est composite ou non.
Et j'ai adapté le code source de l'implémentation probabiliste du test de Miller-Rabin original trouvé ici: http://en.literateprograms.org/Miller-Rabin_primality_test_(Python)
la source
Si vous contrôlez N, le moyen le plus rapide de répertorier tous les nombres premiers est de les précalculer. Sérieusement. Le précalcul est un moyen d'optimisation négligé.
la source
Voici le code que j'utilise normalement pour générer des nombres premiers en Python:
Il ne peut pas rivaliser avec les solutions plus rapides publiées ici, mais au moins c'est du pur python.
Merci d'avoir posté cette question. J'ai vraiment beaucoup appris aujourd'hui.
la source
Pour le code le plus rapide, la solution numpy est la meilleure. Pour des raisons purement académiques, cependant, je publie ma version en python pur, qui est un peu moins de 50% plus rapide que la version du livre de cuisine publiée ci-dessus. Puisque je fais la liste entière en mémoire, vous avez besoin de suffisamment d'espace pour tout contenir, mais cela semble assez bien évoluer.
Et les résultats:
la source
Une implémentation légèrement différente d'un demi-tamis utilisant Numpy:
http://rebrained.com/?p=458
Quelqu'un peut-il comparer cela avec les autres horaires? Sur ma machine, il semble assez comparable aux autres demi-tamis Numpy.
la source
upto=10**6
:primesfrom2to()
- 7 ms;prime6()
- 12 ms ideone.com/oDg2YTout est écrit et testé. Il n'est donc pas nécessaire de réinventer la roue.
nous donne un record de 12,2 ms !
Si ce n'est pas assez rapide, vous pouvez essayer PyPy:
ce qui se traduit par:
La réponse avec 247 votes positifs répertorie 15,9 ms pour la meilleure solution. Comparez cela !!!
la source
J'ai testé certaines fonctions d'unutbu , je les ai calculées avec des millions de millions
Les gagnants sont les fonctions qui utilisent la bibliothèque numpy,
Remarque : Il serait également intéressant de faire un test d'utilisation de la mémoire :)
Exemple de code
Code complet sur mon dépôt github
la source
Pour Python 3
la source
Tamis primaire le plus rapide en Pure Python :
J'ai optimisé Sieve of Eratosthenes pour la vitesse et la mémoire.
Référence
Production
la source
La première fois que vous utilisez python, certaines des méthodes que j'utilise peuvent sembler un peu lourdes. Je viens de convertir mon code c ++ en python et c'est ce que j'ai (bien qu'un peu lent en python)
la source
Je sais que le concours est fermé depuis quelques années. …
Néanmoins, c'est ma suggestion pour un tamis primaire en python pur, basé sur l'omission des multiples de 2, 3 et 5 en utilisant les étapes appropriées lors du traitement du tamis vers l'avant. Néanmoins, il est en réalité plus lent pour N <10 ^ 9 que @Robert William Hanks solutions supérieures rwh_primes2 et rwh_primes1. En utilisant un tableau de tamis ctypes.c_ushort supérieur à 1,5 * 10 ^ 8, il s'adapte en quelque sorte aux limites de la mémoire.
10 ^ 6
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000)" 10 boucles, au mieux de 3: 46,7 msec par boucle
10 ^ 7
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (10000000)" 10 boucles, au mieux de 3: 530 msec par boucle
10 ^ 8
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (100000000)" 10 boucles, au mieux de 3: 5,55 s par boucle
10 ^ 9
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000000)" 10 boucles, au mieux de 3: 61,2 s par boucle
Vous pouvez copier le code ci-dessous dans ubuntus primeSieveSpeedComp pour revoir ces tests.
la source
Voici une version numpy de Sieve of Eratosthenes ayant à la fois une bonne complexité (inférieure au tri d'un tableau de longueur n) et une vectorisation. Comparé à @unutbu, c'est aussi rapide que les packages avec 46 microsecondes pour trouver tous les nombres premiers inférieurs à un million.
Calendrier:
la source
J'ai mis à jour une grande partie du code pour Python 3 et je l'ai lancé sur perfplot (un de mes projets) pour voir lequel est réellement le plus rapide. Il s'avère que, pour les gros
n
,primesfrom{2,3}to
prenez le gâteau:Code pour reproduire l'intrigue:
la source
Je suppose que le plus rapide de toutes les façons est de coder en dur les nombres premiers dans votre code.
Alors pourquoi ne pas simplement écrire un script lent qui génère un autre fichier source contenant tous les nombres, puis importer ce fichier source lorsque vous exécutez votre programme réel.
Bien sûr, cela ne fonctionne que si vous connaissez la limite supérieure de N au moment de la compilation, mais c'est donc le cas pour (presque) tous les problèmes d'Euler du projet.
PS: Je peux me tromper, même si l'analyse de la source avec des nombres premiers câblés est plus lente que leur calcul en premier lieu, mais pour autant que je sache, Python s'exécute à partir de
.pyc
fichiers compilés , donc la lecture d'un tableau binaire avec tous les nombres premiers jusqu'à N devrait être sanglante rapide dans ce cas.la source
Désolé de déranger mais erat2 () a un sérieux défaut dans l'algorithme.
Lors de la recherche du prochain composite, nous devons uniquement tester les nombres impairs. q, p les deux sont impairs; alors q + p est pair et n'a pas besoin d'être testé, mais q + 2 * p est toujours impair. Cela élimine le test «si même» dans la condition de boucle while et économise environ 30% du temps d'exécution.
Pendant que nous y sommes: au lieu de l'élégant «D.pop (q, None)», la méthode get et delete utilise «if q in D: p = D [q], del D [q]» qui est deux fois plus rapide ! Au moins sur ma machine (P3-1Ghz). Je suggère donc cette implémentation de cet algorithme intelligent:
la source
La méthode la plus rapide que j'ai essayée jusqu'à présent est basée sur la fonction livre de recettes Python
erat2
:Voir cette réponse pour une explication de l'accélération.
la source
Je suis peut-être en retard à la fête, mais je devrai ajouter mon propre code pour cela. Il utilise environ n / 2 dans l'espace car nous n'avons pas besoin de stocker des nombres pairs et j'utilise également le module bitarray python, réduisant encore plus la consommation de mémoire et permettant de calculer tous les nombres premiers jusqu'à 1 000 000 000
Il a été exécuté sur un MAC OSX 10.8.3 64 bits 2,4 GHz.
la source
J'ai collecté plusieurs tamis de nombre premier au fil du temps. Le plus rapide sur mon ordinateur est le suivant:
la source
Je suis lent à répondre à cette question, mais cela semblait être un exercice amusant. J'utilise numpy qui pourrait tricher et je doute que cette méthode soit la plus rapide mais elle devrait être claire. Il filtre un tableau booléen se référant uniquement à ses indices et obtient des nombres premiers à partir des indices de toutes les valeurs True. Aucun modulo nécessaire.
la source
ajs_primes3a(10)
->array([2, 3, 5, 7, 9])
.9
n'est pas un premiernumpy
solutions parmi les plus lentes qui retournent un tableau. Remarque: aucune véritable implémentation de Sieve of Eratosthenes n'utilise modulo - pas besoin de le mentionner. Vous pouvez utiliser à lamat[idx*idx::idx]
place demat[idx*2::idx]
. Etnp.nonzero(mat)[0]
au lieu denp.where(mat == True)[0]
.Voici une technique intéressante pour générer des nombres premiers (mais pas les plus efficaces) en utilisant les compréhensions de liste de python:
Vous pouvez trouver l'exemple et quelques explications ici
la source