大素數測試的Miller-Rabin算法

Miller-Rabin算法本質上是一種概率算法,存在誤判的可能性,但是出錯的概率非常小。出錯的概率到底是多少,存在嚴格的理論推導。

費爾馬小定理

  • 如果p 是質數且(a,p)=1 ,則有ap11(modp)
    當然反過來不一定成立。即當ap1%p=1 時,p 未必是質數。但是這個概率比較小。所以利用費爾馬小定理來檢測素數,不能保證時刻都對,只能保證出錯的概率比較小。
    給定正整數n,問n是否爲質數(顯然只需判斷正奇數),最基本的做法就是計算2n1%n 是否爲1。如果不是1,n肯定爲合數;否則,n可能爲質數。

有限域上的平方根定理

  • 如果p 是一個奇質數且e1 ,則方程
    x21(modpe)

    僅有兩個根x=1 或者x=1 ,注意到在模p 的意義下,x=1 等價於x=p1±1 也稱爲1的平凡平方根
  • 很容易有一個推論,如果對模n存在1的非平凡平方根,n一定是合數

Miller-Rabin算法

利用上面兩個定理,就可以構造出Miller-Rabin算法。考慮到n肯定是奇數(偶數的情況自己想去),則n一定可以表示爲n1=2sd ,其中s1d 是奇數。則

an1=a2sd=(((ad)2)...)2

也就是說,an1 相當於ad 平方若干次。例如當n=7 時,an1 就是a6 ,就是a3 的平方。當n=13 時,an1 就是a12 ,就是a3 的平方的平方。
n=13 的情況進行說明(所有運算都是在模n的意義下,以下的文字說明省略了這一點),任取一個a,1<a<13 ,計算a3 ,再將其平方一次得到a6 ,注意到a3a6 的平方根(廢話),根據平方根定理的推論,如果a6=1a3±1 ,則n 肯定是合數。將a6 平方一次得到a12 ,同樣,如果a12=1a6±1 ,則n 肯定是合數。最後,根據費爾馬小定理,如果a121 ,則n 肯定是合數。否則,n 有極大概率爲質數。
爲了增加得到正確判斷的概率,可以將a 重複取不同的值,對每一個a 驗證一次adan1 的過程。不過,考慮到ACM的特殊性,測試數據應該不會選擇僞素數特別是強僞素數。所以很多題目的AC程序實際上只來一次即可。
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章