判斷一個數是不是素數的最快的方法(程式碼可以執行,Miller_Rabin + 新的)
阿新 • • 發佈:2019-01-07
1.自己寫的(某種演算法思想的改進),很快! (只是判斷一個素數,如果資料量比較大,那麼會超時)
#include <cstdio> #include <cmath> #include <cstring> int visit[100000000]; int main() { int n; while(scanf("%d",&n)!=EOF){ int N =(int) sqrt(1.0*n); if(n%2==0) printf("NO\n"); else if(n == 3||n==5 ||n==7 ||n==11 ||n==13||n==17||n==19) printf("YES\n"); else{ memset(visit,0,sizeof(visit)); for(int j=2;j<=N;j++) visit[j] = j; int flag = 2; bool FF = true; bool F2 = true; for(int i=3; i<=N; ) { if(n%i==0){ FF = false; break; } else{ // 如果除以 i 不行,那麼 除以i 的倍數也不能夠整除。 //printf(" i = %d , 剩餘的等待檢測的數是 ",i); for(int j=i;j<=N;j+=i) visit[j] = 0; //這些數,不能再作為 因子嘗試了。 for(int j=i;j<=N;j++){ if(visit[j]!=0){ //找到第一個不是 i 倍數的數 i=j; break; } if(j == N) F2 = false; } } if(!F2) break; /*for(int j=3;j<=N;j++) printf("%d ",visit[j]); printf("\n"); */ } if(!FF) printf("NO\n"); else printf("YES\n"); } } return 0; }
2.Miller_Rabin 隨機數判斷素數的方法(應該是目前最快,把費馬小定理反過來用,S越大,判斷結果越正確,但是,基本上不會判錯)
剛學習的,感覺很好用! (無論資料量大小,都適應,很好用的!!!)
參考學習:vongang.kuangbin
/* 費馬小定理:設p 是素數,a與p互素,則 a^(p-1) ≡ 1 (mod p). 這個定理反過來用,p 幾乎一定是素數(也是成立的) */ #include <cstdio> #include <cstdlib> const int S = 2; //進行S次測試。 其實,2次 基本可以了。 多次更準確 /* 計算 (a*b)%c 的結果 注意:a*b%n = (a%n * b%n) %n. (a+b)%n = (a%n + b%n) %n */ long long mult_mod(long long a,long long b,long long c) { a = a%c; b = b%c; long long ret = 0; while(b){ if(b&1){ //因為對於二進位制而言,每次都是看最後一個一 ret += a; ret %= c; } a = a<<1; //因為b每次最多是1,所以把 此時 2^( a左移的次數)看作 真實算式中b的大小 if(a>=c) a%=c; b = b >>1; // b 對 2 取整 } return ret; } /* 解決 x^n %mod 的結果 把 x 和 n 利用二進位制進行展開,很容易求得。 */ long long pow_mod(long long x,long long n,long long mod) { if(n==1) return x%mod; x %= mod; long long tmp = x; long long ret = 1; while(n){ if(n&1) ret = mult_mod(ret,tmp,mod); //ret = (ret *tmp) %mod tmp = mult_mod(tmp,tmp,mod); //tmp的每次取值是 x^1,x^2,x^4,x^8 n = n>>1; } return ret; } /* 二次探測定理: 如果p是奇素數,則 x^2 ≡ 1(mod p)的解為 x = 1 || x = p - 1(mod p); */ //t 是移位數。 long long check(long long a,long long x,long long n,long long t) { long long ret = pow_mod(a,x,n);//a^x %n 快速冪取模 long long last = ret; //(並且 a 與 n 互素,呼叫之前已經保證了 ) for(int i=1;i<=t;i++){ //移位減掉的量補上 ! 全部補完之後是 a^(n-1) % n ,看結果是否是 1 ret = mult_mod(ret,ret,n); //(ret*ret) % n if(ret ==1 && last!=1 && last!=n-1) //二次探測定理 return true;//不是素數 last = ret; } if(ret!=1) //不是素數 return true; return false; } /* Miller-Rabin測試:不斷選取不超過n-1的基b(s次), 計算是否每次都有bn-1 ≡ 1(mod n), 若每次都成立則n是素數,否則為合數。 */ bool Miller_Rabin(long long n) { if(n<2) return false; if(n==2) return true; if((n&1) ==0) return false;//偶數排除 //因為 判斷公式是 x^(n-1) % n = 1 . //a^(n-1) ≡ 1(mod n) long long x = n - 1; // 求x^u % n long long t = 0; //如果 x 為偶數則x右移,用 t 記錄移位數 while((x&1) ==0){ x = x >> 1; //右移是相除 ,結果越來越小 t++; } for(int i=0;i<S;i++){ //我覺得這個地方換成 n-2 比較好 long long a = rand()%(n-1)+1; //在 [1,n) 中 取隨機數 if(a%n ==0) continue; //自加!!!!!!!!!!!!!!!!!!!!!!! if( check (a,x,n,t) ) return false; } return true; } int main() { for(long long value = 1000000;value<=1000500;value++){ if(Miller_Rabin(value)) printf("%lld 是素數\n",value); else printf("NO\n"); } return 0; }