C ++を使用して素数を見つける最速のアルゴリズムはどれですか?ふるいのアルゴリズムを使用しましたが、それでも高速にしたいです!
C ++を使用して素数を見つける最速のアルゴリズムはどれですか?ふるいのアルゴリズムを使用しましたが、それでも高速にしたいです!
回答:
アトキンのふるいの非常に高速な実装は、Dan Bernsteinの素数です。このふるいはより効率的であるエラトステネスのふるい。彼のページにはいくつかのベンチマーク情報があります。
本当に高速でなければならない場合は、素数のリストを含めることができます:http :
//www.bigprimes.net/archive/prime/
特定の数が素数であるかどうかを知る必要がある場合は、ウィキペディアにさまざまな素数テストがリストされています。特に、数値が素数でないかどうかを知ることができるため、大きな数が素数かどうかを判断するためのおそらく最も速い方法です。
彼、彼は私が古い質問に答えるネクロマンサーの質問であることを知っていますが、効率的な素数検定を実装する方法をネットで検索しているこの質問を見つけました。
今までのところ、最速の素数検定アルゴリズムは、Strong Probable Prime(SPRP)だと思います。私はNvidia CUDAフォーラムから引用しています:
数論におけるより実用的なニッチな問題の1つは、素数の識別に関係しています。Nが与えられた場合、それが素数かどうかを効率的に判断するにはどうすればよいですか?これは単なる理論上の問題ではなく、コードで必要な実際の問題である可能性があります。おそらく、特定の範囲内で主要なハッシュテーブルサイズを動的に見つける必要がある場合です。Nが2 ^ 30のオーダーの場合、30000の除算テストを実行して因子を検索しますか?明らかにそうではありません。
この問題に対する一般的な実用的な解決策は、オイラー確率素数テストと呼ばれる単純なテストと、強力確率素数(SPRP)と呼ばれるより強力な一般化です。これは、整数Nが確率的に素数であるかどうかを分類できるテストであり、テストを繰り返すと正しさの確率が高まります。テスト自体の遅い部分は主に、Nを法とするA ^(N-1)に類似した値の計算に関係します。RSA公開鍵暗号化バリアントを実装する人は誰でもこのアルゴリズムを使用しています。これは、巨大な整数(512ビットなど)と通常の32ビットまたは64ビット整数の両方に役立ちます。
Nの範囲で常に成功することが知られている特定のテスト入力パラメーターを事前計算することにより、テストを確率的棄却から素数性の決定的な証明に変更できます。残念ながら、これらの「最もよく知られているテスト」の発見は、膨大な(実際には無限)ドメイン。1980年に、有用なテストの最初のリストがCarl Pomeranceによって作成されました(二次SeiveアルゴリズムでRSA-129を因数分解することで有名です)。後にJaeschkeが1993年に結果を大幅に改善しました。2004年、ZhangとTangは理論を改善しました検索ドメインの制限。GreathouseとLivingstoneはこれまで、最新の検索結果をウェブで公開しており、巨大な検索ドメインの最高の検索結果であるhttp://math.crg4.com/primes.htmlで公開しています。
詳細については、http://primes.utm.edu/prove/prove2_3.htmlおよびhttp://forums.nvidia.com/index.php?showtopic=70483を参照してください。
非常に大きな素数を生成する方法が必要で、すべての素数<整数nを生成する必要がない場合は、Lucas-Lehmerテストを使用してメルセンヌの素数を検証できます。メルセンヌ素数は2 ^ p -1の形式です。ルーカス・レーマー検定はメルセンヌの素数で発見された最速のアルゴリズムだと思います。
また、最速のアルゴリズムだけでなく最速のハードウェアも使用したい場合は、Nvidia CUDAを使用して実装し、CUDA用のカーネルを作成してGPUで実行してください。
十分な素数を見つければ、いくらかお金を稼ぐこともできます。EFFは$ 50Kから$ 250Kの賞金を提供しています:https : //www.eff.org/awards/coop
数値P
が素数であるか複合であるかをチェックする100%数学テストがあり、これはAKS素数テストと呼ばれます。
概念は単純です。数値が与えられ、P
すべての係数(x-1)^P - (x^P-1)
がで割り切れる場合P
、それP
は素数であり、それ以外の場合、それは合成数です。
たとえば、が与えられた場合、P = 3
多項式が得られます。
(x-1)^3 - (x^3 - 1)
= x^3 + 3x^2 - 3x - 1 - (x^3 - 1)
= 3x^2 - 3x
また、係数はどちらもで割り切れる3
ので、数値は素数です。
そしてP = 4
、素数ではないの例では、
(x-1)^4 - (x^4-1)
= x^4 - 4x^3 + 6x^2 - 4x + 1 - (x^4 - 1)
= -4x^3 + 6x^2 - 4x
そして、ここでは、係数6
がで割り切れない4
ため、素数ではないことがわかります。
多項式(x-1)^P
はP+1
項になり、組み合わせを使用して見つけることができます。したがって、このテストはランタイムでO(n)
実行されるためi
、0からまで反復しp
て残りをテストできるため、これがどれほど役立つかわかりません。
x
略ですか?の中で(x-1)^P - (x^P-1)
。これのサンプルコードはありますか?整数が素数であるかどうかを決定するためのC ++で?
あなたの問題は、特定の数が素数であるかどうかを決定することですか?次に、素数テストが必要です(簡単)。または、指定された数までのすべての素数が必要ですか?その場合、素数のふるいは適切です(簡単ですが、メモリが必要です)。それとも、数の素因数が必要ですか?これには因数分解が必要になります(最も効率的な方法が本当に必要な場合、多数の場合は困難です)。あなたが見ている数はどれくらい大きいですか?16ビット?32ビット?より大きい?
賢明で効率的な方法の1つは、素数のテーブルを事前に計算し、ビットレベルのエンコーディングを使用してファイルに保持することです。ファイルは1つの長いビットベクトルと見なされますが、ビットnは整数nを表します。nが素数の場合、そのビットは1に設定され、それ以外の場合はゼロに設定されます。ルックアップは非常に高速で(バイトオフセットとビットマスクを計算します)、ファイルをメモリにロードする必要はありません。
Rabin-Millerは、標準的な確率素数テストです。(K回実行すると、入力数は確実に合成されるか、おそらくエラー4 -Kの確率で素数になります。(数百回の反復で、ほぼ確実に真実を伝えています)
Rabin Millerの非確率論的(決定論的)バリアントがあります。
グレートインターネットメルセンヌ数検索最大の実績のあるプライムのための世界記録発見した(GIMPS)(2 74207281 - 2017年6月の時点で1)は、使用していますいくつかのアルゴリズムを、これらは特別な形で素数です。ただし、上記のGIMPSページには、一般的な決定論的素数性テストが含まれています。それらは、どのアルゴリズムが「最速」かは、テストする数のサイズに依存することを示しているようです。数値が64ビットに収まる場合は、数百万桁の素数を処理することを目的とした方法を使用しないでください。
私は常にこのメソッドを使用して、ふるいアルゴリズムに従って素数を計算します。
void primelist()
{
for(int i = 4; i < pr; i += 2) mark[ i ] = false;
for(int i = 3; i < pr; i += 2) mark[ i ] = true; mark[ 2 ] = true;
for(int i = 3, sq = sqrt( pr ); i < sq; i += 2)
if(mark[ i ])
for(int j = i << 1; j < pr; j += i) mark[ j ] = false;
prime[ 0 ] = 2; ind = 1;
for(int i = 3; i < pr; i += 2)
if(mark[ i ]) ind++; printf("%d\n", ind);
}
最速かどうかを判断させていただきます。
using System;
namespace PrimeNumbers
{
public static class Program
{
static int primesCount = 0;
public static void Main()
{
DateTime startingTime = DateTime.Now;
RangePrime(1,1000000);
DateTime endingTime = DateTime.Now;
TimeSpan span = endingTime - startingTime;
Console.WriteLine("span = {0}", span.TotalSeconds);
}
public static void RangePrime(int start, int end)
{
for (int i = start; i != end+1; i++)
{
bool isPrime = IsPrime(i);
if(isPrime)
{
primesCount++;
Console.WriteLine("number = {0}", i);
}
}
Console.WriteLine("primes count = {0}",primesCount);
}
public static bool IsPrime(int ToCheck)
{
if (ToCheck == 2) return true;
if (ToCheck < 2) return false;
if (IsOdd(ToCheck))
{
for (int i = 3; i <= (ToCheck / 3); i += 2)
{
if (ToCheck % i == 0) return false;
}
return true;
}
else return false; // even numbers(excluding 2) are composite
}
public static bool IsOdd(int ToCheck)
{
return ((ToCheck % 2 != 0) ? true : false);
}
}
}
2.40 GHzプロセッサを搭載したCore 2 Duoラップトップで、1〜1,000,000の範囲内の素数を見つけて出力するには、約82秒かかります。そして、78,498の素数を見つけました。
i <= (ToCheck / 3)
。それはあるはずですi <= (ToCheck / i)
。それを使用すると、代わりに0.1秒で実行される可能性があります。
#include<stdio.h>
main()
{
long long unsigned x,y,b,z,e,r,c;
scanf("%llu",&x);
if(x<2)return 0;
scanf("%llu",&y);
if(y<x)return 0;
if(x==2)printf("|2");
if(x%2==0)x+=1;
if(y%2==0)y-=1;
for(b=x;b<=y;b+=2)
{
z=b;e=0;
for(c=2;c*c<=z;c++)
{
if(z%c==0)e++;
if(e>0)z=3;
}
if(e==0)
{
printf("|%llu",z);
r+=1;
}
}
printf("|\n%llu outputs...\n",r);
scanf("%llu",&r);
}
定義済みのアルゴリズムについては知りませんが、非常に高速な独自のアルゴリズムを作成しました。20桁の数値を1秒未満で処理できます。このプログラムの最大機能は18446744073709551615です。プログラムは次のとおりです。
#include <iostream>
#include <cmath>
#include <stdlib.h>
using namespace std;
unsigned long long int num = 0;
bool prime() {
if (num % 2 == 0 || num == 1) {
return false;
}
unsigned long int square_root = sqrt(num);
for (unsigned long int i = 3; i <= square_root; i += 2) {
if (num % i == 0) {
return false;
}
}
return true;
}
int main() {
do {
system("cls");
cout << "Enter number : ";
cin >> num;
if (prime()) {
cout << "The number is a prime number" << endl << endl << endl << endl;
} else {
cout << "The number is not a prime number" << endl << endl << endl << endl;
}
system("pause");
} while (1);
return 0;
}
#include <iostream>
using namespace std;
int set [1000000];
int main (){
for (int i=0; i<1000000; i++){
set [i] = 0;
}
int set_size= 1000;
set [set_size];
set [0] = 2;
set [1] = 3;
int Ps = 0;
int last = 2;
cout << 2 << " " << 3 << " ";
for (int n=1; n<10000; n++){
int t = 0;
Ps = (n%2)+1+(3*n);
for (int i=0; i==i; i++){
if (set [i] == 0) break;
if (Ps%set[i]==0){
t=1;
break;
}
}
if (t==0){
cout << Ps << " ";
set [last] = Ps;
last++;
}
}
//cout << last << endl;
cout << endl;
system ("pause");
return 0;
}
(n%2)+1+(3*n)
ちょっといいけど。:)
私はそれが少し後であることを知っていますが、これは検索からここに到着した人々に役立つかもしれません。とにかく、ここでは、テストする必要があるのは素因数のみであるという事実に依存するJavaScriptです。そのため、コードによって生成された初期素数は、後の素数のテスト因数として再利用されます。もちろん、すべての偶数とmod 5の値が最初にフィルターで除外されます。結果は配列Pにあり、このコードはi7 PCで1.5秒未満で1000万個の素数を処理できます(約20で1億個)。Cで書き直された場合、非常に高速になるはずです。
var P = [1, 2], j, k, l = 3
for (k = 3 ; k < 10000000 ; k += 2)
{
loop: if (++l < 5)
{
for (j = 2 ; P[j] <= Math.sqrt(k) ; ++j)
if (k % P[j] == 0) break loop
P[P.length] = k
}
else l = 0
}
#include<iostream>
using namespace std;
void main()
{
int num,i,j,prime;
cout<<"Enter the upper limit :";
cin>>num;
cout<<"Prime numbers till "<<num<<" are :2, ";
for(i=3;i<=num;i++)
{
prime=1;
for(j=2;j<i;j++)
{
if(i%j==0)
{
prime=0;
break;
}
}
if(prime==1)
cout<<i<<", ";
}
}
break;
それなしではO(N ^ 2)はさらに遅くなりますが、それはすでにコーディングエラーと見なすことができます。素数による保存とテストはO(N ^ 2 /(log N)^ 2)であり、数値の平方根以下の素数によるテストはO(N ^ 1.5 /(log N)^ 2)です。