最もコンパクトなマッピングn→isprime(n)を制限Nまで作成する方法は?


152

当然、bool isprime(number)クエリできるデータ構造があるからです。範囲(1、N]のメモリ消費量が最も少ないデータ構造を生成するアルゴリズムある最適なアルゴリズム
定義します(ここでNは定数です。
私が探しているもののほんの一例:すべての奇数を表すことができます)たとえば、指定された範囲の数値(1、10)の1ビットで、3から始まります。1110

次の辞書はもっと絞れるでしょう?いくつかの作業で5の倍数を削除することもできますが、1、3、7、または9で終わる数字がビットの配列に存在する必要があります。

どうすれば問題を解決できますか?


3
あなたの要求は少しあいまいです。単一の数値をテストするシグネチャを指定してから、(1、N]のデータ構造を要求します。dictionary<int、bool>を生成するアルゴリズムが必要ですか、それとも単一の数値かどうかを確認するワンショット関数が必要ですか?プライムですか?
マイケルハーレン

@マイケル申し訳ありません、それは私が思いつくことができる最高の説明です。私が探しているのは、まさにあなたが言っているとおりです。ブール辞書です。辞書のスペースを最小限にしたいと思います。おかげで:)
AraK 2009年

1
:それはあなたがそれがすでに求められています探しているものならstackoverflow.com/questions/1032427/...
ベン・S

14
NSAに質問する必要があります
Charles Bretana 2009年

回答:


79

素数性テストを行う方法はたくさんあります。

クエリするデータ構造は実際にはありません。テストする数値が多い場合は、確率論的テストが高速であるため、おそらく確率論的テストを実行し、その後、決定論的テストを実行して、数値が素数であることを確認します。

最速のアルゴリズムの背後にある数学は、気の弱い人には向かないことを知っておく必要があります。


4
Miller-Rabinは、最初から人気のある高速確率検定です。
qwr 2016

214

一般的な素数テストの最速のアルゴリズムはAKSです。ウィキペディアの記事はそれについて詳しく説明し、元の論文へのリンクを示しています。

大きな数を見つけたい場合は、メルセンヌ素数のような特別な形の素数を調べてください。

私が通常実装するアルゴリズム(理解とコーディングが簡単)は次のとおりです(Pythonの場合)。

def isprime(n):
    """Returns True if n is prime."""
    if n == 2:
        return True
    if n == 3:
        return True
    if n % 2 == 0:
        return False
    if n % 3 == 0:
        return False

    i = 5
    w = 2

    while i * i <= n:
        if n % i == 0:
            return False

        i += w
        w = 6 - w

    return True

それは古典の変形です O(sqrt(N))アルゴリズムのです。それは(2と3を除く)プライムの形式であるという事実に使用し6k - 1たり6k + 1と、この形式の約数でのみ見えますが。

時々、本当にスピードが必要で範囲が限られている場合、フェルマーの小さな定理に基づいて疑似素数テストを実装します。本当にもっと高速が必要な場合(つまり、O(sqrt(N))アルゴリズムを完全に回避する場合)、誤検知(カーマイケル数を参照)を事前計算し、バイナリ検索を実行します。これは私が今まで実装した中で最も速いテストです。唯一の欠点は、範囲が制限されていることです。


7
二つの質問:あなたはより良い変数何を説明できますiし、wあり、そして何がフォームを意味している6k-16k+1?あなたの洞察とコードサンプル(私が理解しようとしている)を
ありがとう

6
@Freedom_Benどうぞ、quora.com /…
Alan Dong

6
それは計算するほうがよいのではないでしょうsqrtn、一度と比較するiことにではなく、計算i * iループのサイクルごとに?
ペドロス

3
@Dschoni ...しかし、ここのコメントフィールドに最速の実装を入れて共有することはできませんか?
GreenAsJade 2016

3
1番は失敗します:(
Damjan Pavlica

27

私の意見では、最良の方法は以前に行ったことを使用することです。

Nインターネットに最初の素数のリストがありN、少なくとも5000万まで伸びています。ファイルをダウンロードして使用すると、他のどの方法よりもはるかに高速になります。

あなたがあなた自身の素数を作るための実際のアルゴリズムをしたい場合は、ウィキペディアは素数で良いもののすべての種類を持って、ここでそれを行うための様々な方法へのリンク、およびプライムテストを含め、ここに、両方の確率をベースと高速決定論的な方法。

最初の10億(またはそれ以上)の素数を見つけて、どこかでネット上に公開するための協調的な努力が必要です。そうすれば、人々は同じ仕事を何度も何度もやめることができます... :-)


2
@hamedbh:興味深い。それらのファイルをダウンロードしようとしましたか?存在しないようです。
paxdiablo 2016

まだですが、恐れています。昼休みにすばやく見ていました。悪意のあるものがあった場合は、そのリンクを削除します。申し訳ありませんが、私は最初にそれをチェックするべきでした。
2016

1
そのようなリスト存在します。私は数年前にそれらを見たが、それらをダウンロードすることを気にしなかった。真実は、それらは(比較的言えば)多くのスペースを占めるため、販売または配布するプログラムに含めるべきではないということです。さらに、それらは常にそして永久に不完全です。実際にプログラムの使用中に出てくる各数値をテストする方が理にかなっています。その方法でテストするのは、所有しているリストの長さよりもはるかに少ないからです。また、paxは素数アルゴリズムの目的を理解していないと思います。ほとんどの場合、実際に素数を見つけるのではなく、効率/速度をテストすることです。
CogitoErgoCogitoSum 2017

2
@CogitoErgoCogitoSum、数が無限であるという数学的証明を見たので、すべての素数のリストは永久に古くなることに同意します。ただし、最初のx素数のリストが作成されると、不完全になる可能性は低くなります:-)
paxdiablo

1
確かに、しかし、線形の方法でファイルから読み取るよりも良い保存方法があります。保存済みの事前生成された素数のセットから本当に読み取りたい場合は、問題を高速化する、より複雑なデータ構造を試してください。
CogitoErgoCogitoSum 2017

10
bool isPrime(int n)
{
    // Corner cases
    if (n <= 1)  return false;
    if (n <= 3)  return true;

    // This is checked so that we can skip 
    // middle five numbers in below loop
    if (n%2 == 0 || n%3 == 0) return false;

    for (int i=5; i*i<=n; i=i+6)
        if (n%i == 0 || n%(i+2) == 0)
           return false;

    return true;
}

これは上記のAKSアルゴリズムの単なるc ++実装です


1
その最も効率的な決定論的アルゴリズムの1つに出くわしますが、AKSの実装ではありません。AKSシステムは、概説されているアルゴリズムよりもはるかに新しいものです。それは間違いなくより効率的ですが、潜在的に天文学的に大きな階乗/二項係数の可能​​性があるため、imoの実装はやや困難です。
CogitoErgoCogitoSum 2017

これはDerri Leahiの(非)回答(Javaの代わりにC以外とどう違うのですか?これはどのように答えWhat is the algorithm that produces a data structure with lowest memory consumption for the range (1, N]ますか?
greybeard 2018

1
(n%i == 0 || n%(i + 2)== 0)は6n + 1および6n-1にどのように対応しますか?
はい、

@YeshwanthVenkatesh:How does (n%i == 0 || n%(i+2) == 0) correspond to 6n+1 & 6n-1?解答の一部はのために異なる役割であり、n他方はであり、6N + 1&6N-1に相当する(6N-1)+0・(6N-1)+ 2 *。
greybeard 2018年

また、このアルゴリズムは、のために正しい結果が得られていないことに注意してください57
エイサンクラーク

7

最も人気のある提案の効率を比較して、数値が素数かどうかを判断しました。私は使用しpython 3.6ましたubuntu 17.10。私は100.000までの数値でテストしました(以下の私のコードを使用して、より大きな数値でテストできます)。

この最初のプロットは関数を比較します(これは私の回答の後半で説明されています)。数値を増やすと、最後の関数が最初の関数ほど速く成長しないことを示しています。

プロット1

また、2番目のプロットでは、素数の場合、時間は着実に増加しますが、非素数は時間の経過とともにそれほど速くなりません(それらのほとんどは早期に除去できるため)。

プロット2

これが私が使った機能です:

  1. この回答この回答は、以下を使用する構成を提案しましたall()

    def is_prime_1(n):
        return n > 1 and all(n % i for i in range(2, int(math.sqrt(n)) + 1))
    
  2. この答えはある種のwhileループを使用しました:

    def is_prime_2(n):
        if n <= 1:
            return False
        if n == 2:
            return True
        if n == 3:
            return True
        if n % 2 == 0:
            return False
        if n % 3 == 0:
            return False
    
        i = 5
        w = 2
        while i * i <= n:
            if n % i == 0:
                return False
            i += w
            w = 6 - w
    
        return True
    
  3. この回答にはforループのあるバージョンが含まれていました:

    def is_prime_3(n):
        if n <= 1:
            return False
    
        if n % 2 == 0 and n > 2:
            return False
    
        for i in range(3, int(math.sqrt(n)) + 1, 2):
            if n % i == 0:
                return False
    
        return True
    
  4. そして、私は他の答えからのいくつかのアイデアを新しいものに混ぜました:

    def is_prime_4(n):
        if n <= 1:          # negative numbers, 0 or 1
            return False
        if n <= 3:          # 2 and 3
            return True
        if n % 2 == 0 or n % 3 == 0:
            return False
    
        for i in range(5, int(math.sqrt(n)) + 1, 2):
            if n % i == 0:
                return False
    
        return True
    

バリアントを比較するためのスクリプトは次のとおりです。

import math
import pandas as pd
import seaborn as sns
import time
from matplotlib import pyplot as plt


def is_prime_1(n):
    ...
def is_prime_2(n):
    ...
def is_prime_3(n):
    ...
def is_prime_4(n):
    ...

default_func_list = (is_prime_1, is_prime_2, is_prime_3, is_prime_4)

def assert_equal_results(func_list=default_func_list, n):
    for i in range(-2, n):
        r_list = [f(i) for f in func_list]
        if not all(r == r_list[0] for r in r_list):
            print(i, r_list)
            raise ValueError
    print('all functions return the same results for integers up to {}'.format(n))

def compare_functions(func_list=default_func_list, n):
    result_list = []
    n_measurements = 3

    for f in func_list:
        for i in range(1, n + 1):
            ret_list = []
            t_sum = 0
            for _ in range(n_measurements):
                t_start = time.perf_counter()
                is_prime = f(i)
                t_end = time.perf_counter()

                ret_list.append(is_prime)
                t_sum += (t_end - t_start)

            is_prime = ret_list[0]
            assert all(ret == is_prime for ret in ret_list)
            result_list.append((f.__name__, i, is_prime, t_sum / n_measurements))

    df = pd.DataFrame(
        data=result_list,
        columns=['f', 'number', 'is_prime', 't_seconds'])
    df['t_micro_seconds'] = df['t_seconds'].map(lambda x: round(x * 10**6, 2))
    print('df.shape:', df.shape)

    print()
    print('', '-' * 41)
    print('| {:11s} | {:11s} | {:11s} |'.format(
        'is_prime', 'count', 'percent'))
    df_sub1 = df[df['f'] == 'is_prime_1']
    print('| {:11s} | {:11,d} | {:9.1f} % |'.format(
        'all', df_sub1.shape[0], 100))
    for (is_prime, count) in df_sub1['is_prime'].value_counts().iteritems():
        print('| {:11s} | {:11,d} | {:9.1f} % |'.format(
            str(is_prime), count, count * 100 / df_sub1.shape[0]))
    print('', '-' * 41)

    print()
    print('', '-' * 69)
    print('| {:11s} | {:11s} | {:11s} | {:11s} | {:11s} |'.format(
        'f', 'is_prime', 't min (us)', 't mean (us)', 't max (us)'))
    for f, df_sub1 in df.groupby(['f', ]):
        col = df_sub1['t_micro_seconds']
        print('|{0}|{0}|{0}|{0}|{0}|'.format('-' * 13))
        print('| {:11s} | {:11s} | {:11.2f} | {:11.2f} | {:11.2f} |'.format(
            f, 'all', col.min(), col.mean(), col.max()))
        for is_prime, df_sub2 in df_sub1.groupby(['is_prime', ]):
            col = df_sub2['t_micro_seconds']
            print('| {:11s} | {:11s} | {:11.2f} | {:11.2f} | {:11.2f} |'.format(
                f, str(is_prime), col.min(), col.mean(), col.max()))
    print('', '-' * 69)

    return df

関数compare_functions(n=10**5)(最大100.000まで)を実行すると、次の出力が得られます。

df.shape: (400000, 5)

 -----------------------------------------
| is_prime    | count       | percent     |
| all         |     100,000 |     100.0 % |
| False       |      90,408 |      90.4 % |
| True        |       9,592 |       9.6 % |
 -----------------------------------------

 ---------------------------------------------------------------------
| f           | is_prime    | t min (us)  | t mean (us) | t max (us)  |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_1  | all         |        0.57 |        2.50 |      154.35 |
| is_prime_1  | False       |        0.57 |        1.52 |      154.35 |
| is_prime_1  | True        |        0.89 |       11.66 |       55.54 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_2  | all         |        0.24 |        1.14 |      304.82 |
| is_prime_2  | False       |        0.24 |        0.56 |      304.82 |
| is_prime_2  | True        |        0.25 |        6.67 |       48.49 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_3  | all         |        0.20 |        0.95 |       50.99 |
| is_prime_3  | False       |        0.20 |        0.60 |       40.62 |
| is_prime_3  | True        |        0.58 |        4.22 |       50.99 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_4  | all         |        0.20 |        0.89 |       20.09 |
| is_prime_4  | False       |        0.21 |        0.53 |       14.63 |
| is_prime_4  | True        |        0.20 |        4.27 |       20.09 |
 ---------------------------------------------------------------------

次に、関数compare_functions(n=10**6)(数値1.000.000まで)を実行すると、次の出力が得られます。

df.shape: (4000000, 5)

 -----------------------------------------
| is_prime    | count       | percent     |
| all         |   1,000,000 |     100.0 % |
| False       |     921,502 |      92.2 % |
| True        |      78,498 |       7.8 % |
 -----------------------------------------

 ---------------------------------------------------------------------
| f           | is_prime    | t min (us)  | t mean (us) | t max (us)  |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_1  | all         |        0.51 |        5.39 |     1414.87 |
| is_prime_1  | False       |        0.51 |        2.19 |      413.42 |
| is_prime_1  | True        |        0.87 |       42.98 |     1414.87 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_2  | all         |        0.24 |        2.65 |      612.69 |
| is_prime_2  | False       |        0.24 |        0.89 |      322.81 |
| is_prime_2  | True        |        0.24 |       23.27 |      612.69 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_3  | all         |        0.20 |        1.93 |       67.40 |
| is_prime_3  | False       |        0.20 |        0.82 |       61.39 |
| is_prime_3  | True        |        0.59 |       14.97 |       67.40 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_4  | all         |        0.18 |        1.88 |      332.13 |
| is_prime_4  | False       |        0.20 |        0.74 |      311.94 |
| is_prime_4  | True        |        0.18 |       15.23 |      332.13 |
 ---------------------------------------------------------------------

次のスクリプトを使用して結果をプロットしました。

def plot_1(func_list=default_func_list, n):
    df_orig = compare_functions(func_list=func_list, n=n)
    df_filtered = df_orig[df_orig['t_micro_seconds'] <= 20]
    sns.lmplot(
        data=df_filtered, x='number', y='t_micro_seconds',
        col='f',
        # row='is_prime',
        markers='.',
        ci=None)

    plt.ticklabel_format(style='sci', axis='x', scilimits=(3, 3))
    plt.show()


6

sympyを使用できます

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

sympy docsから。最初のステップは、重要な要素を探すことです。これが見つかった場合、迅速な復帰が可能になります。次に、ふるいが十分に大きい場合、ふるいで二分探索を使用します。少数の場合、一連の決定論的なミラーラビン検定が、その範囲に反例がないことがわかっている基底を使用して実行されます。最後に、数値が2 ^ 64より大きい場合、強力なBPSWテストが実行されます。これはおそらくプライムテストであり、反例が存在すると私たちは信じていますが、既知の反例はありません


アルゴリズムは、問題の抽象的な解決策を定義する明確に定義された一連のステップです。- 提示されたコードの考えられる一連のステップは何ですか?そのmemory consumption何ですか?
greybeard 2018

2
@老い。sympy docsから。最初のステップは、重要な要素を探すことです。これが見つかった場合、迅速な復帰が可能になります。次に、ふるいが十分に大きい場合、ふるいで二分探索を使用します。少数の場合、一連の決定論的なミラーラビン検定が、その範囲に反例がないことがわかっている基底を使用して実行されます。最後に、数値が2 ^ 64より大きい場合、強力なBPSWテストが実行されます。これはおそらくプライムテストであり、反例が存在すると私たちは信じていますが、既知の反例はありません。
LetzerWille 2018

6

Python 3の場合:

def is_prime(a):
    if a < 2:
        return False
    elif a!=2 and a % 2 == 0:
        return False
    else:
        return all (a % i for i in range(3, int(a**0.5)+1))

説明: 素数は、それ自体と1のみで割り切れる数です。例:2,3,5,7 ...

1)a <2の場合「a」が2未満の場合、素数ではありません。

2)elif a!= 2およびa%2 == 0:「a」が2で割り切れる場合、その素数は絶対にありません。しかし、a = 2の場合、素数であるため、評価する必要はありません。したがって、条件a!= 2

3)all(a%i for i in range(3、int(a 0.5)+1)):**最初に、Pythonでall()コマンドが何をするかを確認します。3から始めて、「a」をその平方根(a ** 0.5)まで除算します。「a」が割り切れる場合、出力はFalseになります。なぜ平方根?a = 16としましょう。16 = 4の平方根。15まで評価する必要はありません。素数ではないことを示すために、4までチェックするだけです。

Extra: 範囲内のすべての素数を見つけるためのループ。

for i in range(1,100):
    if is_prime(i):
        print("{} is a prime number".format(i))

1
これはOleksandr Shmyheliukの回答とどう違うのですか?(どちらもrange()…の「ステップ2」を逃します)
greybeard '25

1
数値が偶数の場合、素数ではありません(2を除く)。したがって、偶数をチェックする必要はありません。範囲内の素数を取得する場合、これははるかに高速になります。偶数をまっすぐに除外します。
ディープグリューアル2018


3

大きな数の場合、候補数Nがsqrt(N)未満の数で割り切れないかどうかを単純にチェックすることはできません。Miller-Rabin素数性テストなど、より多くのスケーラブルなテストが利用可能です。以下にPythonでの実装があります:

def is_prime(x):
    """Fast implementation fo Miller-Rabin primality test, guaranteed to be correct."""
    import math
    def get_sd(x):
        """Returns (s: int, d: int) for which x = d*2^s """
        if not x: return 0, 0
        s = 0
        while 1:
            if x % 2 == 0:
                x /= 2
                s += 1
            else:
                return s, x
    if x <= 2:
        return x == 2
    # x - 1 = d*2^s
    s, d = get_sd(x - 1)
    if not s:
        return False  # divisible by 2!
    log2x = int(math.log(x) / math.log(2)) + 1
    # As long as Riemann hypothesis holds true, it is impossible
    # that all the numbers below this threshold are strong liars.
    # Hence the number is guaranteed to be a prime if no contradiction is found.
    threshold = min(x, 2*log2x*log2x+1)
    for a in range(2, threshold):
        # From Fermat's little theorem if x is a prime then a^(x-1) % x == 1
        # Hence the below must hold true if x is indeed a prime:
        if pow(a, d, x) != 1:
            for r in range(0, s):
                if -pow(a, d*2**r, x) % x == 1:
                    break
            else:
                # Contradicts Fermat's little theorem, hence not a prime.
                return False
    # No contradiction found, hence x must be a prime.
    return True

あなたはそれを使って巨大な素数を見つけることができます:

x = 10000000000000000000000000000000000000000000000000000000000000000000000000000
for e in range(1000):
    if is_prime(x + e):
        print('%d is a prime!' % (x + e))
        break

# 10000000000000000000000000000000000000000000000000000000000000000000000000133 is a prime!

ランダムな整数をテストする場合は、Miller-Rabinを呼び出す前に、候補数が1000未満の素数のいずれかで割り切れるかどうかを最初にテストする必要があります。これにより、10444344345などの明らかな非素数を除外できます。


これはミラーテストです。Miller-Rabin検定は、確率的バージョンであり、十分な信頼が得られるまでランダムに選択された塩基がテストされます。また、ミラーテストはリーマン仮説に直接依存していませんが、二次ディリクレ文字の一般化リーマン仮説(GRH)です(私はそれが一口であり、私もそれを理解していません)。これは、リーマン仮説の潜在的な証明がGRHにさえ適用されない可能性があり、したがってミラーテストが正しいことを証明しないことを意味します。GRHが反証されている場合、さらに悪いケースは当然です。
Arne Vogel、

2

パーティーには遅すぎますが、これが役立つことを願っています。これは、大きな素数を探している場合に関連します。

大きな奇数をテストするには、フェルマー検定および/またはミラーラビン検定を使用する必要があります。

これらのテストは、非常に高価なモジュラー指数を使用しnます。ビット指数の場合、少なくともn大きなint乗算とn大きなint除算が必要です。これは、べき乗の複雑さがO(n³)であることを意味します。

したがって、大きな銃を使用する前に、かなりの数の試用部門を行う必要があります。しかし、単純にそれを行わないでください。それらをすばやく行う方法があります。最初に、大きな整数に使用する単語に、できるだけ多くの素数を合わせます。32ビットワードを使用する場合は、3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 3234846615を乗算し、ユークリッドアルゴリズムを使用してテストする数値で最大公約数を計算します。最初のステップの後、数値はワードサイズより小さくなり、完全な大整数除算を実行せずにアルゴリズムを続行します。GCD!= 1の場合、乗算した素数の1つが数値を除算するので、素数ではないという証明が得られます。次に、31 * 37 * 41 * 43 * 47 = 95041567と続きます。

この方法で数百(または千)の素数をテストしたら、40ラウンドのミラーラビンテストを実行して、数が素数であることを確認できます。40ラウンド後、数が素数であることを確認できます。そうではありません(ハードウェアが誤動作している可能性が高いです...)。


1

私は(2 ^ 61)-1まで機能する素数関数を持っています。

from math import sqrt
def isprime(num): num > 1 and return all(num % x for x in range(2, int(sqrt(num)+1)))

説明:

all()この関数は、このように再定義することができます。

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

このall()関数は、一連のブール値/数値をFalse調べ、0またはと表示された場合に戻りますFalse

sqrt()機能だけでやっている平方根数のを。

例えば:

>>> from math import sqrt
>>> sqrt(9)
>>> 3
>>> sqrt(100)
>>> 10

num % x一部を返し、残りを NUM / xのを。

最後に、2で始まり2で終わるリストrange(2, int(sqrt(num)))作成することを意味しますint(sqrt(num)+1)

範囲の詳細については、このWebサイトをご覧ください。

num > 1一部はちょうど、変数かどうかをチェックされますnum 1と0が素数とは見なされませんbecuase、1よりも大きくなっています。

これが役に立ったと思います:)


これがどのようにthe bestアルゴリズムであるか、または優れたアルゴリズムであるかを議論してください。
greybeard '11年

@greybeard、ここのほとんどの素数関数は(2 ^ 31)-1に到達しないか、数値が大きい場合に時間がかかりすぎますが、(2 ^ 61)-1まで機能するため、数値が素数であるかどうかを確認できます数値の範囲。
WhyAreYouReadingThis

1

Pythonの場合:

def is_prime(n):
    return not any(n % p == 0 for p in range(2, int(math.sqrt(n)) + 1))

数学的形式からPythonへのより直接的な変換ではall(n%p!= 0 ...)を使用しますが、これにはpのすべての値の厳密な評価が必要です。いません真の値が発見された場合、バージョンが早期に終了することができます。


Wrt "all(n%p!= 0 ...)しかし、これにはpのすべての値の厳密な評価が必要です" -これは誤りです。anyそしてall両方の意志早期終了は。だから、最初にpどこn % p0all終了します。
アネロイド

1

素数のjavascriptに最適なアルゴリズム

 function isPrime(num) {
      if (num <= 1) return false;
      else if (num <= 3) return true;
      else if (num % 2 == 0 || num % 3 == 0) return false;
      var i = 5;
      while (i * i <= num) {
        if (num % i == 0 || num % (i + 2) == 0) return false;
        i += 6;
      }
      return true
    }

1
import math
import time


def check_prime(n):

    if n == 1:
        return False

    if n == 2:
        return True

    if n % 2 == 0:
        return False

    from_i = 3
    to_i = math.sqrt(n) + 1

    for i in range(from_i, int(to_i), 2):
        if n % i == 0:
            return False
    return True

1

素数は、1とそれ自体でのみ割り切れる任意の数です。他のすべての数値は合成と呼ばれます。

素数を見つける最も簡単な方法は、入力数が合成数であるかどうかをチェックすることです:

    function isPrime(number) {
        // Check if a number is composite
        for (let i = 2; i < number; i++) {
            if (number % i === 0) {
                return false;
            }
        }
        // Return true for prime numbers
        return true;
    }

プログラムはの値を分割する必要があります number 1からその値までのすべての整数する必要があります。この数が1だけでなくそれ自体で均等に割り切れる場合、それは合成数です。

i素数と合成数の両方が1で割り切れるので、変数の初期値は2でなければなりません。

    for (let i = 2; i < number; i++)

その後i、より小さいnumber、同じ理由で。素数と合成数の両方を、それ自体で均等に分割できます。したがって、確認する必要はありません。

次に、剰余演算子を使用して、変数を均等に分割できるかどうかを確認します。

    if (number % i === 0) {
        return false;
    }

余りがゼロの場合は、 number均等に分割できるため、合成数であり、falseを返します。

入力した数値が条件を満たしていない場合、それは素数であり、関数はtrueを返します。


1
最良のsimplest有効な解釈の1つだと思いますが:)問題は、数値が素数かどうかをチェックするための最良のアルゴリズム何ですか?:分割可能性のチェックは有利ですか?どうですか?他の3³解答の理解できるものは何を言っていますか?number / 2 < i < numbernumber < i*i
greybeard

1

64ビット整数の完璧なソリューションを提案します。C#を使用して申し訳ありません。最初の投稿でそれをpythonとして指定していません。簡単なmodPow関数を見つけて、簡単に分析できることを願っています。

public static bool IsPrime(ulong number)
{
    return number == 2 
        ? true 
        : (BigInterger.ModPow(2, number, number) == 2 
            ? (number & 1 != 0 && BinarySearchInA001567(number) == false) 
            : false)
}

public static bool BinarySearchInA001567(ulong number)
{
    // Is number in list?
    // todo: Binary Search in A001567 (https://oeis.org/A001567) below 2 ^ 64
    // Only 2.35 Gigabytes as a text file http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
}

1
bool isPrime(int n) {
if(n <= 3)
    return (n > 1)==0? false: true;
else if(n%2 == 0 || n%3 == 0)
    return false;

int i = 5;

while(i * i <= n){
    if(n%i == 0 || (n%(i+2) == 0))
        return false;
    i = i + 6;
}

return true;
}

任意の数について、その数が素数であるかどうかを確認するための最小反復は、2からその数の平方根までです。反復を減らすために、さらに、数が2または3で割り切れるかどうかを確認できます。最大数は、数が2または3で割り切れるかどうかを確認することで削除できます。さらに、3より大きい素数は6kとして表すことができます。 +1または6k-1。したがって、反復は6k + 1から数値の平方根まで進むことができます。


1
editを使用して回答に説明を追加した方がよいでしょう。なぜあなたの答えが良いものであるのか、多くの読者にははっきりしないかもしれません、そしてあなたがもっと説明すれば彼らはあなたから学ぶことができます。
Brian Tompsett-汤莱恩

0

最小のメモリ?これは最小ではありませんが、正しい方向への一歩です。

class PrimeDictionary {
    BitArray bits;

    public PrimeDictionary(int n) {
        bits = new BitArray(n + 1);
        for (int i = 0; 2 * i + 3 <= n; i++) {
            bits.Set(i, CheckPrimality(2 * i + 3));
        }
    }

    public PrimeDictionary(IEnumerable<int> primes) {
        bits = new BitArray(primes.Max());
        foreach(var prime in primes.Where(p => p != 2)) {
            bits.Set((prime - 3) / 2, true);
        }
    }

    public bool IsPrime(int k) {
        if (k == 2) {
            return true;
        }
        if (k % 2 == 0) {
            return false;
        }
        return bits[(k - 3) / 2];
    }
}

もちろん、の定義を指定する必要がありCheckPrimalityます。


0

私が作った私の方法は最速の1つだと思います。

void prime(long long int number) {
    // Establishing Variables
    long long int i = 5;
    int w = 2;
    const long long int lim = sqrt(number);

    // Gets 2 and 3 out of the way
    if (number == 1) { cout << number << " is hard to classify. \n";  return; }
    if (number == 2) { cout << number << " is Prime. \n";  return; }
    if (number == 3) { cout << number << " is Prime. \n";  return; }

    // Tests Odd Ball Factors
    if (number % 2 == 0) { cout << number << " is not Prime. \n";  return; }
    if (number % 3 == 0) { cout << number << " is not Prime. \n";  return; }

    while (i <= lim) {
        if (number % i == 0) { cout << number << " is not Prime. \n";  return; }
        // Tests Number
        i = i + w; // Increments number
        w = 6 - i; // We already tested 2 and 3
        // So this removes testing multepules of this
    }
    cout << number << " is Prime. \n"; return;
}

1
間違いかもしれない... 6-私?
うーん

0

言及されているAKSアルゴリズムと同様のアイデア

public static boolean isPrime(int n) {

    if(n == 2 || n == 3) return true;
    if((n & 1 ) == 0 || n % 3 == 0) return false;
    int limit = (int)Math.sqrt(n) + 1;
    for(int i = 5, w = 2; i <= limit; i += w, w = 6 - w) {
        if(n % i == 0) return false;
        numChecks++;
    }
    return true;
}

1
AKSアルゴリズムとは関係ありません。
greybeard 2018

forループでは、「i <= limit」を確認する必要はありません。「i <limit」を確認するだけで十分です。したがって、すべての反復で1つの比較を少なくします。
Andrushenko Alexander

0

範囲内の数値が素数かどうかを調べる。

#!usr/bin/python3

def prime_check(*args):
    for arg in args:
        if arg > 1:     # prime numbers are greater than 1
            for i in range(2,arg):   # check for factors
                if(arg % i) == 0:
                    print(arg,"is not Prime")
                    print(i,"times",arg//i,"is",arg)
                    break
            else:
                print(arg,"is Prime")
                
            # if input number is less than
            # or equal to 1, it is not prime
        else:
            print(arg,"is not Prime")
    return
    
# Calling Now
prime_check(*list(range(101)))  # This will check all the numbers in range 0 to 100 
prime_check(#anynumber)         # Put any number while calling it will check.

このコードを実行すると、リストと特定の番号の両方で機能します
Harsh Singh

0
myInp=int(input("Enter a number: "))
if myInp==1:
    print("The number {} is neither a prime not composite no".format(myInp))
elif myInp>1:
    for i in range(2,myInp//2+1):
        if myInp%i==0:
            print("The Number {} is not a prime no".format(myInp))
            print("Because",i,"times",myInp//i,"is",myInp)
            break
    else:
        print("The Number {} is a prime no".format(myInp))
else:
    print("Alas the no {} is a not a prime no".format(myInp))

1
答えを書くときは、たとえそれが正しいとしても、あなたが何をしているのか、そしてその理由を説明してください。このようにして、あなたの答えを読んでいる人はあなたが解決したことをより簡単に理解することができます。ありがとうございました!
キム・

1
確かにキム、指摘してくれてありがとう。これはStackoverflowでの私の最初のプログラムなので、今後は適切なコメントと説明を追加します。
DKB 2018年

0
public static boolean isPrime(int number) {
 if(number < 2)
   return false;
 else if(number == 2 || number == 3)
        return true;
      else {
        for(int i=2;i<=number/2;i++)
           if(number%i == 0)
             return false;
           else if(i==number/2)
                return true;
      }
    return false;
}

0

このようなものを試すことができます。

def main():
    try:
        user_in = int(input("Enter a number to determine whether the number is prime or not: "))
    except ValueError:
        print()
        print("You must enter a number!")
        print()
        return
    list_range = list(range(2,user_in+1))
    divisor_list = []
    for number in list_range:
        if user_in%number==0:
            divisor_list.append(number)
    if len(divisor_list) < 2:
        print(user_in, "is a prime number!")
        return
    else:
        print(user_in, "is not a prime number!")
        return
main()

これは素数をテストするための恐ろしいソリューションです。1 つの除数を見つけたら、答えはわかりますが、このコードはすべての除数を見つけ決定します!また、常に返されるため、ブール述語に対するOPの要求は無視されますNone
cdlane 2018年

@cdlane私はこのブール値の戻り関数ではないことを知っています。私はまだPythonの初心者であり、完璧ではないことを知っています。とにかくコメントしてくれてありがとう
Patrick Jane

0

以前の回答のほとんどは正しいですが、ここに、数値が素数であることをテストするもう1つの方法があります。復習として、素数は1より大きい整数であり、唯一の因子は1とそれ自体です(source

解決:

通常、ループを構築し、1、2、3で割り切れるかどうかを確認するために番号をテストし始めます...テストしている番号まで...などですが、確認する時間を短縮するには、番号を数値がその値の半分を超えるもので割り切れないため、数値の半分。たとえば、100が素数であることを確認したい場合は、50までループできます。

実際のコード

def find_prime(number):
    if(number ==1):
        return False
    # we are dividiing and rounding and then adding the remainder to increment !
    # to cover not fully divisible value to go up forexample 23 becomes 11
    stop=number//2+number%2
    #loop through up to the half of the values
    for item in range(2,stop):
        if number%item==0:
           return False
        print(number)
    return True


if(find_prime(3)):
    print("it's a prime number !!")
else:
    print("it's not a prime")  

チェックする必要があるのは、数値の平方根です。これは、数値の半分よりもかなり小さいです。たとえば、n = 100の場合、50ではなく10にチェックするだけで済みます。なぜですか。ちょうど平方根で、2つの因子は等しくなります。その他の因子の場合、1つはsqrt(n)より小さく、もう1つは大きくなります。したがって、sqrt(n)までの診断が行われるまでに1つも見ていなかった場合、後で見つけることはできません。
DanaJ

0

これをO(sqrt(n))に実装するには、Javaストリームを使用できます。noneMatchは、結果を判別する必要がないと判断したときに操作を停止するshortCircuitingメソッドであると考えてください。

Scanner in = new Scanner(System.in);
int n = in.nextInt();
System.out.println(n == 2 ? "Prime" : IntStream.rangeClosed(2, ((int)(Math.sqrt(n)) + 1)).noneMatch(a -> n % a == 0) ? "Prime" : "Not Prime");

0

Java-8ストリームとラムダの助けを借りて、わずか数行で次のように実装できます。

public static boolean isPrime(int candidate){
        int candidateRoot = (int) Math.sqrt( (double) candidate);
        return IntStream.range(2,candidateRoot)
                .boxed().noneMatch(x -> candidate % x == 0);
    }

パフォーマンスはO(sqrt(N))に近いはずです。多分誰かがそれが便利だと思います。


「range」は「rangeClosed」に置き換えて、候補ルートを含める必要があります。また、候補<2のケースも処理する必要があります。
udalmik

これは、alirezafnaticaの以前の回答とどう違うのですか?
greybeard

0

これが私の答えです。

def isprime(num):
    return num <= 3 or (num + 1) % 6 == 0 or (num - 1) % 6 == 0

以下のいずれかのプロパティがTrueの場合、関数はTrueを返します。これらのプロパティは、素数が何であるかを数学的に定義します。

  1. 数は3以下です
  2. 数+ 1は6で割り切れる
  3. 数-1は6で割り切れる

>>> isprime(25)を返しますTrue。非常に単純な必要条件(2または3による除算可能)をチェックしていますが、これでは不十分です。
DanaJ

いいですね、このプロパティで一致しています。3より大きいすべての素数は6n + 1または6n + 5の形式ですが、6n + 1または6n + 5の形式の数値(25)が存在しますが、プライムではない
ルイスフェリペ

0

高速検証を行う必要がある場合は、入力の平方根よりも小さい数値間の基本的な除算に基づいて、この単純なコードを記述します。

def isprime(n):
    if n%2==0:
        return n==2
    else:
        cota = int(n**0.5)+1
        for ind in range(3,2,cota):
            if n%ind==0:
                print(ind)
                return False
        return True != n==1

isprime(22783)
  • 最後True != n==1はケースを避けることn=1です。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.