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?
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.
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.
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
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.
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
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"
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
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