轉載地址: http://m.blog.csdn.net/blog/spirtsong/38273187
素數是除了自身和1以外,沒有其它素數因子的自然數。自從歐幾里得證明了有無窮個素數以后,人們就企圖尋找一個可以構造所有素數的公式,尋找判定一個自然數是不是素數的方法。因為素數的地位非常重要。
鑒別一個自然數是素數還是合數,這個問題在中世紀就引起人們注意,當時人們試圖尋找質數公式,到了高斯時代,基本上確認了簡單的質數公式是不存在的,因此,高斯認為對素性判定是一個相當困難的問題。從此以后,這個問題吸引了大批數學家。 素性判斷算法可分為兩大類,確定性算法及隨機算法。前者可給出確定的結果但通常較慢,后者則反之。
這里主要講米勒拉賓算法,最后提供c++實現代碼。
要測試
是否為素數,首先將
分解為
。在每次測試開始時,先隨機選一個 介於
的整數
,之后如果對所有的
,若
且
,則 N 是合數。否則,
有
的概率為素數。
Miller- Rabin算法隨機生成底數a,進行多次調用函數進行測試,Miller-Rabin檢測也存在偽素數的問題,但是與費馬檢測不同,MR檢測的正確概率不 依賴被檢測數p,而僅依賴於檢測次數。已經證明,如果一個數p為合數,那么Miller-Rabin檢測的證據數量不少於比其小的正整數的3/4,換言 之,k次檢測后得到錯誤結果的概率為(1/4)^k。我們在實際應用中一般可以測試15~20次。
1 #include <iostream> 2 #include <cmath> 3 using namespace std; 4 5 long long qpow(int a,int b,int r)//快速冪 6 { 7 long long ans=1,buff=a; 8 while(b) 9 { 10 if(b&1)ans=(ans*buff)%r; 11 buff=(buff*buff)%r; 12 b>>=1; 13 } 14 return ans; 15 } 16 bool Miller_Rabbin(int n,int a)//米勒拉賓素數測試 17 { 18 int r=0,s=n-1,j; 19 if(!(n%a)) 20 return false; 21 while(!(s&1)){ 22 s>>=1; 23 r++; 24 } 25 long long k=qpow(a,s,n); 26 if(k==1) 27 return true; 28 for(j=0;j<r;j++,k=k*k%n) 29 if(k==n-1) 30 return true; 31 return false; 32 } 33 bool IsPrime(int n)//判斷是否是素數 34 { 35 int tab[]={2,3,5,7}; 36 for(int i=0;i<4;i++) 37 { 38 if(n==tab[i]) 39 return true; 40 if(!Miller_Rabbin(n,tab[i])) 41 return false; 42 } 43 return true; 44 } 45 int main() 46 { 47 long long n; 48 while(1) 49 { 50 cin >> n; 51 cout << IsPrime(n)<< endl; 52 } 53 54 return 0; 55 }
在一次檢驗中,該算法出錯的可能頂多是四分之一。如果我們獨立地和隨機地選擇 a 進行重復檢驗,一旦此算法報告 n 是合數,我們就可以確信 n 肯定不是素數。但如果此算法重復檢驗 25 次報告都報告說 n 可能是素數,則我們可以說 n “幾乎肯定是素數”。因為這樣一個 25 次的檢驗過程給出關於它的輸入的錯誤信息的概率小於 (1/4)25。這種機會小於 1015 分之一。即使我們以這樣一個過程驗證了十億個不同的素數,預料出錯的概率仍將小於百萬分之一。因此如果真出了錯,與其說此算法重復地猜測錯,倒不如說由於 硬件的失靈或宇宙射線的原因,我們的計算機在它的計算中丟了一位。這樣的概率性算法使我們對傳統的可靠性標准提出一個問號:我們是否真正需要有素性的嚴格 證明。(以上文字引用自 Donald E.Knuth 所著的《計算機程序設計藝術 第2卷 半數值算法(第3版)》第 359 頁“4.5.4 分解素因子”中的“算法P(概率素性檢驗)”后面的說明)
