1. 程式人生 > >素數判定算法 MILLER RABIN

素數判定算法 MILLER RABIN

發現 空間 ios 默認 pac 通過 處理 復雜 void

入門級篩素數--試除法,復雜度O(n^2)

bool rmprime( long long n )
{
    for(long long i = 2; i <= sqrt(n) ; i++)    if(n%i == 0) return false;
    return true;
}

學了一段時間算法以後,應該會了解到篩法求素數,復雜度略高於O(n)

#include<iostream>
#include<cstring>
using namespace std;
const int MAXN = 500000;
bool isp[MAXN];
int p[MAXN];
int cnt = 0;//保存素數個數 void getp() { for(int i = 1; i < MAXN; i++) isp[i] = 1 ; //默認全部素數 for(int i = 2; i < MAXN; i++){ if(!isp[i]) continue; //如果不是素數就continue掉 p[cnt++] = i; for(int j = i * 2 ; j < MX; j += i) isp[j] = 0;//記錄,往後滾處理 } } int main(){ getp();
for(int i = 0; i < cnt; i++) printf("%d ",p[i]); return 0; }

當然,不難發現,如果MaX值過大的話,不只空間會炸,而且從頭開始掃很玄學,是不怎麽可取的。

於是引入MILLER RABIN算法。可以單獨判斷一個大數是否素數,但是不保證正確。我們只能通過多次執行算法讓這個錯誤的概率很小。//不過幸運的是,除非你是非酋王,這個算法一般都是不會出問題的。

算法的理論基礎: 1. Fermat定理:若n是奇素數,a是任意正整數(1≤ a≤ n?1),則 a^(n-1) ≡ 1 mod n。 2. 推演自Fermat定理(具體過程我沒看懂,Orz), 如果n是一個奇素數,將n?1表示成2^s*r的形式,r是奇數,a與n是互素的任何隨機整數,那麽a^r ≡ 1 mod n或者對某個j (0 ≤ j≤ s?1, j∈Z) 等式a^(2jr) ≡ ?1 mod n 成立。 聰明的讀者已經發現上述的定理是一個數是素數的必要條件而非充分條件,所以這就是這個算法的不精確的原有,對於一些特定的檢驗算子a,存在一些合數也滿足上述定理。所以我們要多找幾個a反復檢驗,這樣能讓錯誤率大大降低。 那麽我們按照上述的定理2,首先重復n次實驗。對於每一次實驗,隨機取檢驗算子a,帶入定理2進行檢驗,看看在算子a下,n能否滿足 a^r ≡ 1 mod n或者對某個j (0 ≤ j≤ s?1, j∈Z) 等式a^(2jr) ≡ ?1 mod n ** 如果任意一次實驗不滿足,則判定不是素數,如果都滿足,可近似可以認為是素數(錯誤率極小)。
#include <iostream> 
#include 
<cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <map> using namespace std; const int times = 20; int number = 0; map<long long, int>m; long long Random( long long n ) //生成[ 0 , n ]的隨機數 { return ((double)rand( ) / RAND_MAX*n + 0.5); } long long q_mul( long long a, long long b, long long mod ) //快速計算 (a*b) % mod { long long ans = 0; while(b) { if(b & 1) { b--; ans =(ans+ a)%mod; } b /= 2; a = (a + a) % mod; } return ans; } long long q_pow( long long a, long long b, long long mod ) //快速計算 (a^b) % mod { long long ans = 1; while(b) { if(b & 1) { ans = q_mul( ans, a, mod ); } b /= 2; a = q_mul( a, a, mod ); } return ans; } bool witness( long long a, long long n )//miller_rabin算法的精華 {//用檢驗算子a來檢驗n是不是素數 long long tem = n - 1; int j = 0; while(tem % 2 == 0) { tem /= 2; j++; } //將n-1拆分為a^r * s long long x = q_pow( a, tem, n ); //得到a^r mod n if(x == 1 || x == n - 1) return true; //余數為1則為素數 while(j--) //否則試驗條件2看是否有滿足的 j { x = q_mul( x, x, n ); if(x == n - 1) return true; } return false; } bool miller_rabin( long long n ) //檢驗n是否是素數 { if(n == 2) return true; if(n < 2 || n % 2 == 0) return false; //如果是2則是素數,如果<2或者是>2的偶數則不是素數 for(int i = 1; i <= times; i++) //做times次隨機檢驗 { long long a = Random( n - 2 ) + 1; //得到隨機檢驗算子 a if(!witness( a, n )) //用a檢驗n是否是素數 return false; } return true; } int main( ) { long long tar; while(cin >> tar) { if(miller_rabin( tar )) //檢驗tar是不是素數 cout << "Yes, Prime!" << endl; else cout << "No, not prime.." << endl; } return 0; }

素數判定算法 MILLER RABIN