費馬定理的逆定理幾乎可以用來判斷一個數是否爲素數,但是有一些數是判斷不出來的,因此,Miller_Rabin測試方法對費馬的測試過程做了改進,克服其存在的問題。
推理過程如下(摘自維基百科):
摘自另一篇博文(手動滑稽):
原理明白了,就直接上代碼了(KuangBin大神的板子):
代碼思路是,
- Miller_Rabin()函數隨機選取 s 個a,a用做“基底”
- check() 函數是用來判斷x是否等於1,也就是判斷a是否是n的憑證。
- Mul_mod()函數是 快速乘 ,求 a^t % n 之後的值是否爲正負一,因爲兩個數直接乘的話會很大,可能會爆Long Long, 因此用快速乘邊乘邊mod。
- pow_mod()函數是 快速冪 ,在剛開始第一次判斷 a^(n-1) % n 時會用到。
1 /* ************************************************* 2 * Miller_Rabin 算法進行素數測試 3 * 速度快可以判斷一個 < 2^63 的數是不是素數 4 * 5 **************************************************/ 6 const int S = 8; //隨機算法判定次數一般 8 ∼ 10 就夠了 7 // 計算 ret = (a*b)%c 8 //a,b,c < 2^63 9 long long mult_mod(long long a,long long b,long long c) 10 { 11 a %= c; 12 b %= c; 13 long long ret = 0; 14 long long tmp = a; 15 while(b) 16 { 17 if(b & 1) 18 { 19 ret += tmp; 20 if(ret > c)ret -= c;//直接取模慢很多 21 } 22 tmp <<= 1; 23 if(tmp > c)tmp -= c; 24 b >>= 1; 25 } 26 return ret; 27 } 28 // 計算 ret = (a^n)%mod 29 long long pow_mod(long long a,long long n,long long mod) 30 { 31 long long ret = 1; 32 long long temp = a%mod; 33 while(n) 34 { 35 if(n & 1)ret = mult_mod(ret,temp,mod); 36 temp = mult_mod(temp,temp,mod); 37 n >>= 1; 38 } 39 return ret; 40 } 41 // 通過 a^(n − 1)=1(mod n)來判斷 n 是不是素數 42 // n − 1 = x ∗ 2 t 中間使用二次判斷 43 // 是合數返回 true, 不一定是合數返回 false 44 bool check(long long a,long long n,long long x,long long t) 45 { 46 long long ret = pow_mod(a,x,n); 47 long long last = ret; 48 for(int i = 1; i <= t; i++) 49 { 50 ret = mult_mod(ret,ret,n); 51 if(ret == 1 && last != 1 && last != n - 1)return true;//合數 52 last = ret; 53 } 54 if(ret != 1)return true; 55 else return false; 56 } 57 //************************************************** 58 // Miller_Rabin 算法 59 // 是素數返回 true,(可能是僞素數) 60 // 不是素數返回 false 61 //************************************************** 62 bool Miller_Rabin(long long n) 63 { 64 if( n < 2)return false; 65 if( n == 2)return true; 66 if( (n&1) == 0)return false;//偶數 67 long long x = n - 1; 68 long long t = 0; 69 while( (x&1)==0 ) 70 { 71 x >>= 1; 72 t++; 73 } 74 srand(time(NULL));/* *************** */ 75 for(int i = 0; i < S; i++) 76 { 77 long long a = rand()%(n - 1) + 1; 78 if( check(a,n,x,t) ) 79 return false; 80 } 81 return true; 82 }