web-dev-qa-db-fra.com

Vérifier si un nombre est un nombre premier en Python

J'ai écrit le code suivant, qui devrait vérifier si le nombre entré est un nombre premier ou non, mais il y a un problème que je ne pouvais pas résoudre:

def main():
n = input("Please enter a number:")
is_prime(n)

def is_prime(a):
    x = True 
    for i in (2, a):
            while x:
               if a%i == 0:
                   x = False
               else:
                   x = True


    if x:
        print "prime"
    else:
        print "not prime"

main()

Si le nombre entré n'est pas un nombre premier, il affiche "non premier" comme il est supposé, mais si le nombre est un nombre premier, il n'affiche rien. Pourriez-vous m'aider s'il vous plaît?

38
steve

Voici mon point de vue sur le problème:

from math import sqrt; from itertools import count, islice

def isPrime(n):
    return n > 1 and all(n%i for i in islice(count(2), int(sqrt(n)-1)))

C'est un algorithme très simple et concis, et par conséquent, il n'est pas censé être proche de l'algorithme de contrôle de primalité le plus rapide ou le plus optimal. Il a une complexité temporelle de O(sqrt(n)). Allez sur ici pour en savoir plus sur les tests de primalité effectués correctement et sur leur histoire.


Explication

Je vais vous parler de cette ligne de code presque ésotérique qui vérifie les nombres premiers:

  • Tout d’abord, utiliser range() est vraiment une mauvaise idée, car cela créera une liste de nombres, qui utilise beaucoup de mémoire. Utiliser xrange() est préférable, car il crée un générateur, qui ne doit mémoriser que les arguments initiaux que vous fournissez, et génère chaque nombre à la volée. Si vous utilisez Python 3 ou supérieur range() a été converti en générateur par défaut. À propos, ce n’est pas la meilleure solution du tout: essayer d’appeler xrange(n) pour une n telle que n > 231-1 (qui est la valeur maximale pour une C long) déclenche OverflowError. Par conséquent, le meilleur moyen de créer un générateur de plage consiste à utiliser itertools:

    xrange(2147483647+1) # OverflowError
    
    from itertools import count, islice
    
    count(1)                        # Count from 1 to infinity with step=+1
    islice(count(1), 2147483648)    # Count from 1 to 2^31 with step=+1
    islice(count(1, 3), 2147483648) # Count from 1 to 3*2^31 with step=+3
    
  • Vous n'avez pas besoin d'aller jusqu'à n si vous voulez vérifier si n est un nombre premier. Vous pouvez réduire considérablement les tests et vérifier uniquement de 2 à √(n) (racine carrée de n). Voici un exemple:

    Trouvons tous les diviseurs de n = 100 et listons-les dans un tableau:

     2  x  50 = 100
     4  x  25 = 100
     5  x  20 = 100
    10  x  10 = 100 <-- sqrt(100)
    20  x  5  = 100     
    25  x  4  = 100
    50  x  2  = 100
    

    Vous remarquerez facilement que, après la racine carrée de n, tous les diviseurs que nous trouvons ont déjà été trouvés. Par exemple, 20 a déjà été trouvé en train de faire 100/5. La racine carrée d'un nombre est le point milieu exact où les diviseurs que nous avons trouvés commencent à être dupliqués. Par conséquent, pour vérifier si un nombre est premier, il vous suffira de vérifier de 2 à sqrt(n).

  • Pourquoi sqrt(n)-1 alors, et pas seulement sqrt(n)? En effet, le deuxième argument fourni à l'objet itertools.islice est le nombre d'itérations à exécuter. islice(count(a), b) s'arrête après b itérations. C'est la raison pour laquelle:

    for number in islice(count(10), 2):
        print number,
    
    # Will print: 10 11
    
    for number in islice(count(1, 3), 10):
        print number,
    
    # Will print: 1 4 7 10 13 16 19 22 25 28
    
  • La fonction all(...) est identique à celle-ci:

    def all(iterable):
        for element in iterable:
            if not element:
                return False
        return True
    

    Il vérifie littéralement pour tous les nombres de la variable iterable et renvoie False lorsqu'un nombre est évalué à False (ce qui signifie que si le nombre est égal à zéro). Pourquoi l'utilisons-nous alors? Tout d’abord, nous n’avons pas besoin d’utiliser une variable d’index supplémentaire (comme nous le ferions avec une boucle), mis à part cela: juste pour la concision, elle n’est pas vraiment nécessaire, mais elle semble beaucoup moins encombrante à travailler uniquement avec une seule ligne de code au lieu de plusieurs lignes imbriquées.

Version étendue

J'inclus une version "décompactée" de la fonction isPrime() pour la rendre plus facile à comprendre et à lire:

from math import sqrt
from itertools import count, islice

def isPrime(n):
    if n < 2:
        return False

    for number in islice(count(2), int(sqrt(n) - 1)):
        if n % number == 0:
            return False

    return True
88
Marco Bonelli

Il existe de nombreux moyens efficaces de tester la primalité (et ce n'est pas l'un d'entre eux), mais la boucle que vous avez écrite peut être récrite de manière concise en Python:

def is_prime(a):
    return all(a % i for i in xrange(2, a))

C'est-à-dire que a est premier si tous les nombres entre 2 et a (non inclus) donnent un reste non nul lorsqu'ils sont divisés en a.

68
user97370

C'est le moyen le plus efficace de voir si un nombre est premier, si vous n'avez que quelques requêtes. Si vous demandez beaucoup de chiffres s'ils sont premiers, essayez Sieve of Eratosthenes .

import math

def is_prime(n):
    if n == 2:
        return True
    if n % 2 == 0 or n <= 1:
        return False

    sqr = int(math.sqrt(n)) + 1

    for divisor in range(3, sqr, 2):
        if n % divisor == 0:
            return False
    return True
28
Mark

Si a est un nombre premier, le while x: de votre code sera exécuté indéfiniment, puisque x restera True.

Alors pourquoi est-ce while ici?

Je pense que vous vouliez mettre fin à la boucle lorsque vous avez trouvé un facteur, mais que vous ne saviez pas comment, alors vous avez ajouté que tant qu'il existe une condition. Alors voici comment vous le faites:

def is_prime(a):
    x = True 
    for i in range(2, a):
       if a%i == 0:
           x = False
           break # ends the for loop
       # no else block because it does nothing ...


    if x:
        print "prime"
    else:
        print "not prime"
8
Jochen Ritzel
def is_prime(x):
    n = 2
    if x < n:
        return False
    else:    
        while n < x:
           print n
            if x % n == 0:
                return False
                break
            n = n + 1
        else:
            return True
0
user3732168
def prime(x):
    # check that number is greater that 1
    if x > 1:
        for i in range(2, x + 1):
            # check that only x and 1 can evenly divide x
            if x % i == 0 and i != x and i != 1:
                return False
        else:
            return True
    else:
        return False # if number is negative
0
Fadyboy