web-dev-qa-db-ja.com

数値がPythonの素数であるかどうかを確認する

入力した数値が素数かどうかを確認する必要がある次のコードを作成しましたが、解決できない問題があります。

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()

入力された数が素数でない場合、想定どおり「素数ではない」と表示されますが、数が素数である場合は何も表示されません。手伝ってくれませんか?

47
steve

問題に対する私の見解は次のとおりです。

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
96
Marco Bonelli

素数性をテストする多くの効率的な方法がありますが(これはそれらの1つではありません)、あなたが書いたループはPythonで簡潔に書き直すことができます:

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

つまり、2からaまでのすべての数値(包括的ではない)がaに分割されたときにゼロ以外の剰余を与える場合、aは素数です。

70
user97370

これは、少数のクエリしかない場合に、数値が素数であるかどうかを確認する最も効率的な方法です。素数であるかどうか多くの数を尋ねる場合 エラトステネスの篩

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
30
Mark

aが素数の場合、xTrueのままなので、コード内の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"
9
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
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