1
votes

La somme de grands nombres premiers prend du temps! Comment le rendre plus efficace?

J'essaie de terminer 10ème problème du projet Euler , mais le code que j'ai actuellement prend tellement beaucoup de temps, il n'a pas été en mesure de se terminer.

J'ai regardé autour de moi, mais je n'ai pas été en mesure de trouver comment rendre le code plus court.

Voici le code que j'ai:

def IsPrime(num):
    for i in range(2, num/2):
        if num % i == 0:
            prime = False
            return prime
    prime = True
    return prime

def SumOfPrime(limit):
    primesum=2+3    #For some reason my prime finder doesn't allow numbers below 5
    for check in range(5,limit):
        prime=IsPrime(check)
        if prime == True:
            primesum += check
    return primesum^2

print(SumOfPrime(2000000))

La bonne réponse devrait être 142913828922 , cependant, comme mentionné précédemment je ne n'obtiens pas une sortie entièrement. Existe-t-il un moyen de rendre ce code plus rapide?


5 commentaires

for i in range (2, num / 2): Je définirais la limite supérieure à int (sqrt (num)) + 1 , je pourrais aussi donner un plus efficace algorithme mais vous voulez accélérer celui-ci, non?


Cela a beaucoup aidé! J'obtiens le résultat correct et il faut maintenant 32,98 s pour qu'il se termine. J'adorerais voir un algorithme plus rapide car il n'est bien sûr pas parfait.


Hmm, vous pouvez également enregistrer les nombres premiers trouvés dans une liste et vérifier si un nombre est un nombre premier divisant uniquement par les nombres premiers que vous avez trouvés précédemment, si vous voulez une meilleure façon de trouver les nombres premiers en.wikipedia.org/wiki/Sieve_of_Eratosthenes


Ça a l'air intéressant, merci beaucoup! Peut-être publier ces deux choses comme réponse afin que je puisse marquer la question comme résolue? =)


Puisque 2 est le seul nombre premier pair, dans votre méthode IsPrime , vous pouvez vérifier 2 comme diviseur, puis vérifier uniquement les diviseurs impairs: 3, 5, 7, 9,11, ... jusqu'au racine carrée. Pas aussi efficace qu'un tamis, mais devrait réduire de moitié le temps passé à vérifier un nombre.


3 Réponses :


0
votes

Quelques conseils pour accélérer votre mise en œuvre:

  • Il suffit de rechercher un diviseur jusqu'à la racine carrée d'un nombre, le produit de deux nombres plus grands pour donner un résultat plus grand.
  • Vous pouvez également rechercher uniquement les diviseurs premiers, peut-être en ajoutant les nombres premiers trouvés dans une liste ou quelque chose du genre.

Si vous voulez un algorithme plus efficace, veuillez consulter https://en.wikipedia.org/wiki / Sieve_of_Eratosthenes


0 commentaires

0
votes

il faut maintenant 32,98 secondes pour que cela se termine. J'aimerais voir un plus vite algorithme

Vous devez utiliser un Tamis d'Ératosthène . En ignorant cela, cette retouche devrait vous faire gagner moins de 10 secondes:

def isPrime(number):
    if number <= 2:
        return number == 2

    if number % 2 == 0:
        return False

    for divisor in range(3, int(number ** 0.5) + 1, 2):
        if number % divisor == 0:
            return False

    return True

def sumOfPrimes(limit):
    return sum(number for number in range(limit) if isPrime(number))

print(sumOfPrimes(2000000))

Traitez les nombres pairs comme un cas particulier dans isPrime () puis traiter simplement les diviseurs impairs . L'utilisation d'une compréhension ou d'une expression de générateur fait descendre une plus grande partie de votre code en boucle au niveau C et vous permet généralement d'obtenir un peu plus de vitesse.


3 commentaires

Après quelques tests, j'ai utilisé le même code avec la seule différence if number == 2: return True juste en testant les nombres de 1-10000, le code s'est terminé en 13,549189329147339 sec Lors du test avec le code suivant: def IsPrime (num): for i in range (2, int ((num ** 0.5) +1)): if num% i == 0: return False return True Cela prend 13.15842890739441 < / code> secs Je me demande pourquoi le premier est à peu près le même que le second, même s'il n'analyse que la moitié des nombres ... Quelqu'un a-t-il une raison à cela?


@ Thomas.B, tester des nombres jusqu'à 10 000 ne devrait prendre qu'une fraction de seconde, pas 13 secondes. Le changement que vous avez effectué ne montre aucune différence de synchronisation sur mon système car la plage de nombres est trop petite. À environ 100 000, les surfaces de différence.


Je viens de remarquer l'erreur. Je voulais écrire 1 000 000. Je ne sais pas comment j'ai changé autant le nombre de zéros.



0
votes

Utilisez le tamis d'Ératosthène:

$ python
Python 2.7.13 (default, Mar 13 2017, 20:56:15)
[GCC 5.4.0] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def sumPrimes(n):
...     i, p, ps, m, sum = 0, 3, [2], n // 2, 2
...     sieve = [True] * m
...     while p <= n:
...         if sieve[i]:
...             sum += p
...             for j in range((p*p-3)/2, m, p):
...                 sieve[j] = False
...         i, p = i+1, p+2
...     return sum
...
>>> from time import time
>>> start = time(); print sumPrimes(2000000); print time() - start
142913828922
0.262000083923

Environ un quart de seconde sur ma machine.


6 commentaires

Sur ma machine, en Python 3, cela explose avec, "TypeError: l'objet 'float' ne peut pas être interprété comme un entier". En Python 2, il renvoie le mauvais résultat pour n == 2 ou moins.


Il n'y a aucun flottant n'importe où dans l'algorithme, sauf si vous passez un flottant comme argument n . J'ai Python 2.7.13 installé. Ça fonctionne bien. sumPrimes (2) renvoie correctement 2. Je n'ai pas pris la peine de vérifier les erreurs des cas pour n inférieur à 2 ou pour n un flottant. J'ai modifié ma réponse pour afficher les en-têtes et les informations de synchronisation.


En Python 3, (p * p-3) / 2 est une valeur à virgule flottante et la transmettre à range () génère l'erreur que j'ai citée ci-dessus. (Pas parce que n est un flottant.) Considérez plutôt // (division entière). Si vous suivez le lien de l'OP vers le problème d'Euler, la fonction additionne les nombres premiers inférieurs à n . Ainsi, le résultat pour n == 2 est 0 , votre résultat 2 est incorrect.


@cdlane la réponse indique clairement qu'il s'agit d'un code Python 2.7.13, alors pourquoi devrions-nous nous préoccuper de Python 3? Quant au 2, il peut être facilement en boîtier spécial, donc ce n'est pas un problème non plus, oui? J'ai suivi le lien, et ce qui est demandé il y a une solution pour 2 000 000, pas pour 2.


@WillNess, la réponse n'a pas clairement indiqué que c'était du code Python 2.7.3 jusqu'à ce que après j'écrive mon commentaire. Et les deux problèmes peuvent être facilement résolus sous Python 2.


@cdlane ils n'ont cependant pas besoin d'être corrigés sous Python 2.