素数検証アルゴリズム-ビッグデータに直面
4114 ワード
素数の検証は、いわゆる「サイクル練習」のテーマにされる可能性があります.そのアルゴリズムはあまりにも簡単だからだ(直接暴力サイクルがアルゴリズムと言えるかどうか分からない).古典的な方法は試除であり,サイクル変数iで2からn−1まで,型取りが0のものがあれば直接return falseとする.最後に、まだ0が出ていないので、return trueです.このアルゴリズムはn−1をsqrt(n)として最適化することもできる.原理は、xをsqrt(n)より大きい数とし、n=xyとするとyは必ずsqrt(n)より小さいので、sqrt(n)を検証すればyを検証することができ、xを検証したことに相当する.
このような暴力アルゴリズムは,N個の数が検証されると,時間的複雑度がO(sqrt(N)*N)となり,N=1億円のようなデータに対して明らかに力不足である.したがって,フィルタリング法を用いて,2,3,5,7などの素数の倍数を順次除去し,最後に素数表を1枚得ることができる.テーブル作成後,クエリ素数はO(1)の時間的複雑度のみである.しかし,以上の桁のNについては,素数表をすぐに求めることができず,2.1 sの消費時間を費やした.だから、私たちは最適化しなければなりません.
2を除いたすべての偶数は合数であることが知られている.したがって、素数テーブル内では偶数を除去することができる.すなわちprime[0]は3が素数であるか否かを表し、prime[1]は5を表す・・・また、ふるい数もNにふるう必要はなく、sqrt(N)にふるい合わせればよい.key 1(i)=i*2+3とする.key 2(i)=(i−3)/2は、素数テーブル内のi番目の位置で表される奇数と奇数iの素数テーブル内の記憶位置にそれぞれ対応する.ふるいにかけると、i*(2,3,4...)はi*(3,5,7...)に簡略化されます.最初にふるい落とした数はkey 2(key 1(i*i)*8+3,その後の累積数はkey 2(key 1(i+2)−key 2(key 1(i)),簡略化後i*2+3となり,導出が完了するとプログラムが書きやすくなる.ソースコードを次に示します.
各種方法の時間とメモリ占有統計表(試験環境:MinGw 4.9.2、Intel Xeon E 3 1230 V 2、IO出力時間を除く)を添付する.
時間
メモリ
暴力試験除法
N/A(長すぎます)
1Mb
地味ふるい分け
2.1s
98Mb
さいてきフィルタほう
1.0s
50Mb
このような暴力アルゴリズムは,N個の数が検証されると,時間的複雑度がO(sqrt(N)*N)となり,N=1億円のようなデータに対して明らかに力不足である.したがって,フィルタリング法を用いて,2,3,5,7などの素数の倍数を順次除去し,最後に素数表を1枚得ることができる.テーブル作成後,クエリ素数はO(1)の時間的複雑度のみである.しかし,以上の桁のNについては,素数表をすぐに求めることができず,2.1 sの消費時間を費やした.だから、私たちは最適化しなければなりません.
2を除いたすべての偶数は合数であることが知られている.したがって、素数テーブル内では偶数を除去することができる.すなわちprime[0]は3が素数であるか否かを表し、prime[1]は5を表す・・・また、ふるい数もNにふるう必要はなく、sqrt(N)にふるい合わせればよい.key 1(i)=i*2+3とする.key 2(i)=(i−3)/2は、素数テーブル内のi番目の位置で表される奇数と奇数iの素数テーブル内の記憶位置にそれぞれ対応する.ふるいにかけると、i*(2,3,4...)はi*(3,5,7...)に簡略化されます.最初にふるい落とした数はkey 2(key 1(i*i)*8+3,その後の累積数はkey 2(key 1(i+2)−key 2(key 1(i)),簡略化後i*2+3となり,導出が完了するとプログラムが書きやすくなる.ソースコードを次に示します.
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
const int N=100000001;
const int N1=(N-3)/2;
bool prime[N1+1];
int tmp;
int main(void){
memset(prime,true,sizeof(prime));
for (int i=0;i<(int(sqrt(N))-3)>>1;++i){
if (prime[i]){
tmp=((i*i)<<3)+3;
while (tmp<N1){
prime[tmp]=false;
tmp+=(i<<1)+3;
}
}
}
printf("%d\t",2);
for (int i=0;i<N1;++i)
if (prime[i]) printf("%d\t",i*2+3);
return 0;
}
各種方法の時間とメモリ占有統計表(試験環境:MinGw 4.9.2、Intel Xeon E 3 1230 V 2、IO出力時間を除く)を添付する.
時間
メモリ
暴力試験除法
N/A(長すぎます)
1Mb
地味ふるい分け
2.1s
98Mb
さいてきフィルタほう
1.0s
50Mb