Mon algorithme actuel pour vérifier la primalité des nombres dans Python est de ralentir pour des chiffres compris entre 10 et 1 milliard. Je veux que cela soit amélioré en sachant que je n'aurai jamais des chiffres de plus de 1 milliard.
Le contexte est que je ne peux pas avoir une implémentation suffisante pour résoudre le problème 60 du projet Euler: je reçois la réponse au problème en 75 secondes où j'en ai besoin dans 60 secondes. http://projecteuler.net/index.php?section=problèmes&id=60 P>
J'ai très peu de mémoire à ma disposition, je ne peux donc pas stocker tous les nombres premiers inférieurs à 1 milliard. p>
Je suis actuellement à l'aide de la division d'essai standard à l'aide de 6K ± 1 . Y a-t-il quelque chose de meilleur que cela? Dois-je déjà obtenir la méthode Rabin-Miller pour des chiffres qui sont ce grand. P> Comment puis-je améliorer cet algorithme? P> précision: i 'M NOUVEAU à Python et souhaitez travailler avec Python 3+ uniquement. P> code final strong> P> pour ceux qui sont intéressés, en utilisant maks Idées, j'ai généré le code suivant qui correspond à environ 1/3 plus rapide, me permettant d'obtenir le résultat du problème d'Euler en moins de 60 secondes! P>
from bisect import bisect_left
# sqrt(1000000000) = 31622
__primes = sieve(31622)
def is_prime(n):
# if prime is already in the list, just pick it
if n <= 31622:
i = bisect_left(__primes, n)
return i != len(__primes) and __primes[i] == n
# Divide by each known prime
limit = int(n ** .5)
for p in __primes:
if p > limit: return True
if n % p == 0: return False
# fall back on trial division if n > 1 billion
for f in range(31627, limit, 6): # 31627 is the next prime
if n % f == 0 or n % (f + 4) == 0:
return False
return True
5 Réponses :
Vous pouvez d'abord diviser votre aussi, précalcompute plus de nombres premiers. p>
Aussi, vous stockez réellement votre gamme N code> uniquement par votre
prime_under_100 code>. p>
() code> résultat en mémoire - Utilisez
irrange () code> plutôt et utilisez cette mémoire pour exécuter Sieve of Eratosthenes Algorithme . P>
Eh bien, je ne suis pas court en mémoire;) Et j'utilise Python 3. Je n'ai jamais vu Xrange en Python 3.
Xrange est devenu simplement une gamme de py3k
Pour les nombres aussi importants que 10 ^ 9, une approche peut être de générer tous les nombres premiers jusqu'à SQRT (10 ^ 9), puis vérifiez simplement la divisibilité du numéro d'entrée par rapport aux numéros de cette liste. Si un numéro n'est pas divisible par une autre prime inférieure ou égale à sa racine carrée, elle doit elle-même être une prime (elle doit avoir au moins un facteur <= sqrt et un autre> = sqrt à ne pas être prime). Remarquez comment vous n'avez pas besoin de tester la divisibilité pour tous les chiffres, juste jusqu'à la racine carrée (environ 32 000 - assez gérable, je pense). Vous pouvez générer la liste des nombres premiers à l'aide d'un tamis . P>
Vous pouvez également opter pour un test primitif probabiliste . Mais ils peuvent être plus difficiles à comprendre et, pour ce problème, il suffit d'utiliser une liste générée des nombres premiers devrait suffire. p>
Oui, 32K numéros sont vraiment quelque chose que je peux stocker. Bonne idée.
@Fror, si le nombre est inférieur à 32K, utilisez une recherche binaire. Utilisation du module bisect code>.
Pour résoudre les problèmes d'Euler du projet, j'ai fait ce que vous avez suggéré dans votre question: Implémentez le Miller Rabin Test (en C # mais je soupçonne que ce sera aussi rapide en python). L'algorithme n'est pas si difficile. Pour les chiffres ci-dessous 4 759 123,141, il suffit de vérifier qu'un chiffre est un pseudo-prime fort pour les bases 2, 7, 61. Combinez qu'avec la division d'essai par de petits nombres premiers. P>
Je ne sais pas combien de problèmes que vous avez résolus jusqu'à présent, mais que vous avez un test de primalité rapide à votre disposition, sera d'une grande valeur pour beaucoup de problèmes. P>
Ok, dans ce cas, comment appelez-vous de petits nombres premiers? Quelle est la limite que je devrais définir?
@ Frór: Vous devriez expérimenter de trouver une valeur optimale, mais je commencerais en essayant tous les nombres premiers de moins de 100 environ. IIRC il pourrait même être que j'ai fini par sauter une division d'essai pour toutes les valeurs, à l'exception des bases (dans le cas de la présente affaire 2, 7, 61).
Python: prouvé correct jusqu'à grand n
Eh bien, 4 759 123,141 est très peu ... peut être vérifié en divisant même par des nombres impairs jusqu'à SQRT en un rien de temps. Mais merci pour le lien @pi - je ne comprends toujours pas pourquoi il n'y a pas de fonction np.miller_rabin code> (ou
sciped code> si cela est trop scientifique).
Eh bien, j'ai un suivi de mon commentaire sous (très bon) la réponse de Peter Van der Heijden à propos de ne rien faire pour vraiment de grands nombres premiers (chiffres en général) dans les bibliothèques de python "populaires". S'avère que j'étais tort - il y en a un dans https://docs.sympy.org /Latest/Modules/ntheory.html#sympy.ntheory.primetest.isprime P>
Bien sûr, cela peut générer de faux positifs ci-dessus symboly code> (grande bibliothèque d'algèbre symbolique, entre autres): p>
10 ** 16 code>, mais c'est déjà beaucoup mieux que tout ce que je pourrais ne rien faire (sauf peut-être que
PIP Instally Sydy Code >;)) p>
SydMy 1.1 (juillet 2017) est passé à BPSW. Il n'y a donc pas de faux positifs pour les entrées 64 bits. Dans certains cas, il utilisera des milleurs déterministes-rabin mais ils ont également été vérifiés jusqu'à 2 ^ 64. Pour les entrées 64 bits, le seul moyen d'être «mieux» que cela optimise les pré-tests pour le rendre plus rapide. Pour des intrants plus importants, il n'y a pas d'avantage convaincant à la plupart des fins de faire plus (une longue discussion).
Merci pour la mise à jour! J'ai d'abord lu d'anciennes sources de sympty 0.x, puis liées aux documents les plus récents. Cela ne change pas mon point que Sydy est génial, c'est juste mieux que je pensais;)
En effet, à la plupart des fins, je pense que c'est la bonne réponse. L'OP est en train de faire du projet Euler afin que cela ne soit probablement pas correct pour les problèmes antérieurs, mais peut-être bien pour les plus tard et bien sûr toute autre utilisation pratique.
def isprime(num): if (num==3)or(num==2): return(True) elif (num%2 == 0)or(num%5 == 0): return (False) elif ((((num+1)%6 ==0) or ((num-1)%6 ==0)) and (num>1)): return (True) else: return (False) I think this code is the fastest ..
Tous les nombres premiers (sauf 2 et 3) peuvent être exprimés sous la forme 6n (+/-) 1
Vérifie tous les nombres premiers jusqu'à 1000000 en 0.42194461822509766 secondes dans ma machine. Pas de boucles, pas d'itérations dans le corps de la fonction
Oui, mais l'inverse n'est pas vrai - chaque chiffre qui peut être exprimé sous 6n + -1 n'est pas nécessairement préféré. Par exemple 25 n'est pas un prime (6 * 4 + 1).
Merci d'avoir trouvé le bogue! Pardonne-moi de perdre votre temps. Je modifierai le code. Cependant, je suis un codeur amateur autodidacte
Vous ne pouvez pas le réparer en vérifiant la divisibilité par 5. Le prochain qui n'est pas préféré est 6 * 8 + 1 = 49 = 7 * 7. Désolé, mais ce n'est pas une méthode qui fonctionne réellement.
J'apprécie votre guidage
Wow!! C'est méchant i> rapide. Il calcule ceci: Imprimer (IS_PRIME (78692816150593075150849)) Presque instantanément. Fast Fast!
Je le connaissais sous le nom Python 3 ou Python 3.1, mais cela ressemble à des références PY3K ces versions.
ne devrait-il pas être
f code> et
f + 4 code> ... Pourriez-vous confirmer? Pourquoi le
4 code>?
Bien plus clairement, j'utilise une base 7 + 6k au lieu de 5 + 6k, donc j'ai besoin d'utiliser +0, +4, +6, +10, etc. au lieu de +0, +2, +6, +8, +8. L'avantage est que je ne teste pas 31625.
AVERTISSEMENT: L'exemple purement python (son premier extrait) ne fonctionne pas pour tous les nombres premiers. La ligne
pour f dans la plage (5, int (n ** .5), 6): code> doit être
pour F dans la plage (5, int (n ** .5) + 1 , 6): code>; comme il quitte (trop tôt) avant de pouvoir montrer que le nombre est divisible par la racine carrée de lui-même.
Et? Le deuxième exemple fonctionne, est efficace la question a été prouvée comme utile. Il n'y a aucune raison de descendre sur cette base seulement. J'ai explicitement demandé à "améliorer l'algorithme" indiquant que j'étais nouvelle à la programmation Python. Cela signifie que j'avais un problème avec celui-ci. La baisse sur cette base uniquement est contre ce qui favorise (2 bowvotes en 1 jour depuis que vous avez posté votre commentaire après 2 mois d'inactivité sur cette question, il est i> une relation). Cette question était clairement appropriée pour le moment où je l'ai écrit. Quoi qu'il en soit, je vais réparer l'algorithme dans le premier extrait. Des exemples de nombres sont les bienvenus.
@ogregoire: Je ne sais pas si Daniel vous a réellement rédacté, mais j'ai trouvé son avertissement utile, j'ai presque utilisé le premier extrait parce que j'avais juste besoin d'une fonction isprime rapide et sale et la seconde ne fonctionnait pas pour moi de la boîte sur Python 2.x;)
Obtenez-vous GMPY2 et utilisez gmpy2.is_prime (n)
Connexes: moyen le plus rapide de répertorier tous les nombres premiers ci-dessous n