入力した数値が素数かどうかを確認する必要がある次のコードを作成しましたが、解決できない問題があります。
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()
入力された数が素数でない場合、想定どおり「素数ではない」と表示されますが、数が素数である場合は何も表示されません。手伝ってくれませんか?
問題に対する私の見解は次のとおりです。
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)))
これは非常にシンプルで簡潔なアルゴリズムであるため、最速または最適な素数チェックアルゴリズムに近いものではありません。 O(sqrt(n))
の時間の複雑さがあります。 Head over here 正しく行われた素数性テストとその履歴の詳細については。
素数をチェックする、ほとんど難解な1行のコードについて、いくつか説明します。
まず、range()
を使用することは、多くのメモリを使用する数値のリストを作成するため、本当に悪い考えです。 xrange()
を使用すると、generatorが作成され、指定した初期引数のみを記憶する必要があり、オンザフライですべての数値を生成するため、より適切です。 Python 3以上を使用している場合、range()
はデフォルトでジェネレーターに変換されています。ちなみに、これは最善の解決策ではありません。n > 231-1
(Cのn
の最大値)がlong
を発生させるように、OverflowError
に対してxrange(n)
を呼び出そうとします。したがって、範囲ジェネレーターを作成する最良の方法は、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
n
が素数であるかどうかを確認したい場合は、実際にn
に到達する必要はありません。テストを劇的に削減し、2から√(n)
(n
の平方根)のみをチェックできます。以下に例を示します。
n = 100
のすべての約数を見つけて、テーブルにリストしてみましょう:
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
n
の平方根の後に、、実際に見つかったすべての除数が実際に見つかったことがわかります。たとえば、20
はすでに100/5
を実行していることが検出されました。数値の平方根は、発見された除数が複製され始める正確な中間点です。したがって、数値が素数であるかどうかを確認するには、2からsqrt(n)
までを確認するだけです。
なぜsqrt(n)-1
ではなく、sqrt(n)
なのですか?これは、itertools.islice
オブジェクトに提供される2番目の引数が、実行する反復回数であるためです。 islice(count(a), b)
は、b
回の反復の後に停止します。それが理由です:
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
関数all(...)
は、次のものと同じです。
def all(iterable):
for element in iterable:
if not element:
return False
return True
文字通りiterable
内のすべての数値をチェックし、数値がFalse
に評価されるとFalse
を返します(数値がゼロの場合のみを意味します)。なぜそれを使用するのですか?まず、追加のインデックス変数を使用する必要はありません(ループを使用する場合のように)、それ以外:簡潔にするために、実際にそれを必要とすることはありませんが、ネストされた複数の行ではなく、1行のコード。
理解しやすく読みやすくするために、isPrime()
関数の「アンパック」バージョンを含めています。
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
素数性をテストする多くの効率的な方法がありますが(これはそれらの1つではありません)、あなたが書いたループはPythonで簡潔に書き直すことができます:
def is_prime(a):
return all(a % i for i in xrange(2, a))
つまり、2からaまでのすべての数値(包括的ではない)がaに分割されたときにゼロ以外の剰余を与える場合、aは素数です。
これは、少数のクエリしかない場合に、数値が素数であるかどうかを確認する最も効率的な方法です。素数であるかどうか多くの数を尋ねる場合 エラトステネスの篩 。
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
a
が素数の場合、x
はTrue
のままなので、コード内のwhile x:
は永久に実行されます。
では、なぜそれがwhile
なのでしょうか?
要因を見つけたときにforループを終了したかったのですが、方法がわからなかったので、条件があるのでそれを追加しました。そのため、次のようにします。
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