Ik heb de volgende code geschreven, die moet controleren of het ingevoerde nummer een priemgetal is of niet, maar er is een probleem waar ik niet uitkom:
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()
Als het ingevoerde getal geen priemgetal is, wordt “geen priemgetal” weergegeven, zoals het hoort, maar als het getal een priemgetal is, wordt er niets weergegeven. Hoe kan ik dit oplossen?
Antwoord 1, autoriteit 100%
Hier is mijn kijk op het probleem:
from math import sqrt
from itertools import count, islice
def is_prime(n):
return n > 1 and all(n % i for i in islice(count(2), int(sqrt(n)-1)))
Dit is een heel eenvoudig en beknopt algoritme en daarom is het niet bedoeld om in de buurt te komen van het snelste of meest optimale algoritme voor priemcontrole. Het heeft een tijdcomplexiteit van O(sqrt(n))
. Ga naar hiervoor meer informatie over goed uitgevoerde priemtests en hun geschiedenis.
Uitleg
Ik ga je wat inzicht geven in die bijna esoterische enkele regel code die op priemgetallen controleert:
-
Allereerst is het gebruik van
range()
in Python 2 echt een slecht idee, omdat het een lijst met nummers zal maken, die veel geheugen gebruikt. Metxrange()
is beter, omdat het een generator creëert, die alleen de eerste argumenten die u verstrekt, en genereert elk getal on-the-fly. Als u gebruikt
Python 3,range()
is standaard geconverteerd naar een generator. Trouwens, dit is nog steeds niet de beste oplossing: proberen te bellenxrange(n)
voor sommigen
zodanig datn > 231-1
(Die is de maximale waarde voor een Clong
) verhoogtOverflowError
. Daarom is de beste manier om een bereikgenerator te makenitertools
: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
-
U hoeft niet echt helemaal tot op
n
te gaan als u wilt controleren ofn
een priemgetal is. U kunt de tests drastisch verminderen en alleen controleren van 2 naar√(n)
(vierkantswortel vann
). Hier is een voorbeeld:Laten we alle Divisors of
n = 100
vinden, en vermeld ze in een tabel: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
U zult gemakkelijk opmerken dat, na de vierkantswortel van
n
, alle delicanten die we vinden, daadwerkelijk al gevonden. Bijvoorbeeld,20
is al gevonden met het doen van100/5
. De vierkantswortel van een nummer is het exacte middelpunt waar de divisors die we vonden beginnen te worden gedupliceerd. Daarom, om te controleren of een nummer prime is, hoeft u alleen maar te controleren van 2 naarsqrt(n)
. -
Waarom
sqrt(n)-1
DAN, EN NIET ALLEENsqrt(n)
? Dat is alleen omdat het tweede argument verstrekt aanitertools.islice()
het aantal iteraties is om uit te voeren.islice(count(a), b)
Stopt nab
ITERATIES. Dat is de reden waarom: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
-
De functie
all(...)
is hetzelfde van de volgende:def all(iterable): for element in iterable: if not element: return False return True
Het controleert letterlijk voor alle elementen in de
iterable
, retourneren vanFalse
wanneer een van hen evalueert naarFalse
(die voor een integer betekent alleen als het nul is). Waarom gebruiken we het dan? Allereerst hoeven we geen extra indexvariabele te gebruiken (zoals we zouden doen met een lus), behalve dat: alleen voor concision, er is geen echte behoefte aan, maar het ziet er veel minder omvangrijk uit om alleen te werken een enkele regel code in plaats van verschillende geneste lijnen.
Uitgebreide versie
Ik voeg een “uitgepakte” versie van de functie is_prime()
toe om het gemakkelijker te begrijpen en te lezen:
from math import sqrt
from itertools import count, islice
def is_prime(n):
if n < 2:
return False
for number in islice(count(2), int(sqrt(n) - 1)):
if n % number == 0:
return False
return True
Antwoord 2, autoriteit 61%
Er zijn veel efficiënte manieren om priemgetallen te testen (en dit is er niet één van), maar de lus die je hebt geschreven kan beknopt worden herschreven in Python:
def is_prime(a):
return all(a % i for i in xrange(2, a))
Dat wil zeggen, a is een priemgetal als alle getallen tussen 2 en a (niet inclusief) een rest geven die niet nul is wanneer ze worden gedeeld in a.
Antwoord 3, autoriteit 30%
Dit is de meest efficiënte manier om te zien of een getal een priemgetal is, als je maar een paar vragen hebt. Als je veel getallen vraagt of ze priemgetallen zijn, probeer dan Zeef van 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
Antwoord 4, autoriteit 13%
Als a
een priemgetal is, zal de while x:
in je code voor altijd blijven bestaan, aangezien x
True
.
Dus waarom is dat while
daar?
Ik denk dat je de for-lus wilde beëindigen toen je een factor vond, maar niet wist hoe, dus je hebt dat terwijl toegevoegd omdat het een voorwaarde heeft. Dus hier is hoe je het doet:
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"