米勒-拉賓素性檢測演算法
阿新 • • 發佈:2019-01-07
米勒-拉賓素性檢測就是目前應用比較廣的一種隨機化素性檢測演算法。
它是基於下面兩個定理:
- (費馬小定理)如果 p 為素數,且 a 無法被 p 整除,則對於所有大於0小於 p 的整數 a,有
ap−1≡1modp- 如果1在模n下有非平凡平方根,即存在x ≠ ±1 滿足 x2≡1modn 則n必為合數。
上面兩個定理的具體證明就不給出了。
在素性檢測中,實際上我們利用的是費馬小定理的逆命題,也就是滿足該等式的整數都是素數。費馬小定理的逆命題是偽命題,但它在大多數情況下是成立的。當a = 2時,前十億個正整數中能滿足該等式的合數只有5597個(這些數被稱為偽素數)。
所以如果我們可以通過驗證等式a n−1≡1(modn)是否成立去檢驗一個數是否為素數。對於10億以內的正整數,這樣做出錯的概率只有0.011%.
而通過多次改變a的值來進行檢驗,還可以進一步降低出錯的概率。
當然,這個方法還是有不少漏網之魚的。為了提高準確率,我們就需要用到上面的第二條定理了。
我們先將 p-1 表示為 u*2^t 的形式。那麼,a^(p-1) mod n 就可以表示為:(au)2tmodn
首先,我們計算x0=aumodn,然後使用反覆平方法計算
x1≡x20modn
x2≡x21modn
…
xi≡x2i−1modn
…
xt≡x2t−1modn
很顯然,xi−1是xi在模n下的平方根,那麼,根據定理2,在這一計算過程中,如果有任意一個x i≡1modn且xi−1≢±1modn,則n必為合數。
下面是C++程式碼實現(根據《演算法導論》中的虛擬碼編寫):
bool witness(int a, int n) { unsigned int x = n - 1, t = 0; for(unsigned int i = 1; i <<= 1, t++) //計算t的值 if((x | i) == x) break; unsigned int x0 = mod_exp(a, x >> t, n); //u = x >> t,x0 = a^u mod n for(int i = 0; i < t; i++) { x = x0 * x0 % n; if(x == 1 && x0 != 1 && x0 != n - 1) //x0是1的非平凡平方根,則n必為合數 return true; x0 = x; } if(x != 1) //不符合費馬小定理,n必為合數 return true; return false; } bool is_prime(int n, int s) //s為檢測的次數,s越大準確度越高,但也越耗時間 { srand(time_t(time(NULL))); for(int i = 0; i < s; i++) { int a = rand() % (n - 2) + 2;//實際上隨機生成的a是不允許重複的,這樣寫只是為了簡便 if(witness(a, n)) //如果n為合數,直接返回檢測結果 return false; } return true; }