Miller-Rabin算法本質上是一種概率算法,存在誤判的可能性,但是出錯的概率非常小。出錯的概率到底是多少,存在嚴格的理論推導。
費爾馬小定理
- 如果
p 是質數且(a,p)=1 ,則有ap−1≡1(modp) 。
當然反過來不一定成立。即當ap−1%p=1 時,p 未必是質數。但是這個概率比較小。所以利用費爾馬小定理來檢測素數,不能保證時刻都對,只能保證出錯的概率比較小。
給定正整數n,問n是否爲質數(顯然只需判斷正奇數),最基本的做法就是計算2n−1%n 是否爲1。如果不是1,n肯定爲合數;否則,n可能爲質數。
有限域上的平方根定理
- 如果
p 是一個奇質數且e≥1 ,則方程
x2≡1(modpe)
僅有兩個根x=1 或者x=−1 ,注意到在模p 的意義下,x=−1 等價於x=p−1 ,±1 也稱爲1的平凡平方根 - 很容易有一個推論,如果對模n存在1的非平凡平方根,n一定是合數
Miller-Rabin算法
利用上面兩個定理,就可以構造出Miller-Rabin算法。考慮到n肯定是奇數(偶數的情況自己想去),則n一定可以表示爲
也就是說,
以
爲了增加得到正確判斷的概率,可以將
typedef long long llt;
//利用二進制計算a*b%mod
llt multiMod(llt a,llt b,llt mod){
llt ret = 0LL;
a %= mod;
while( b ){
if ( b & 1LL ) ret = ( ret + a ) % mod, --b;
b >>= 1LL;
a = ( a + a ) % mod;
}
return ret;
}
//計算a^b%mod
llt powerMod(llt a,llt b,llt mod){
llt ret = 1LL;
a %= mod;
while( b ){
if ( b & 1LL ) ret = multiMod(ret,a,mod),--b;
b >>= 1LL;
a = multiMod(a,a,mod);
}
return ret;
}
//Miller-Rabin測試,測試n是否爲素數
bool Miller_Rabin(llt n,int repeat){
if ( 2LL == n || 3LL == n ) return true;
if ( !( n & 1LL ) ) return false;
//將n分解爲2^s*d
llt d = n - 1LL;
int s = 0;
while( !( d & 1LL ) ) ++s, d>>=1LL;
srand((unsigned)time(0));
for(int i=0;i<repeat;++i){//重複repeat次
llt a = rand() % ( n - 3 ) + 2;//取一個隨機數,[2,n-1)
llt x = powerMod(a,d,n);
llt y = 0LL;
for(int j=0;j<s;++j){
y = multiMod(x,x,n);
if ( 1LL == y && 1LL != x && n-1LL != x ) return false;
x = y;
}
if ( 1LL != y ) return false;
}
return true;
}