1. 程式人生 > >素數判定的一些討論(Miller-Rabin演算法)

素數判定的一些討論(Miller-Rabin演算法)

很久沒有寫部落格了。。。最近軍訓加開學,感覺刷題速度有降低,要補一補。

迴歸正題,正式進入數論階段,討論一下關於素數判定的那些事。

一類問題: 判定一個整數n(n>1)是否為素數。

演算法1:

直接根據素數的定義列舉i2(n1),如果n%i==0n為合數。
時間複雜度:O(n)

bool is_prime(int n) {
    int i;
    for(i = 2; i < n; i++)
        if(n % i == 0) return false;
    return true;
}

演算法2:

發現若存在i<n使得n%i==0

,則必有n%(n/i)==0
所以只需列舉i2sqrt(n)即可。
時間複雜度:O(n)

bool is_prime(int n) {
    int i;
    for(i = 2; i * i <= n; i++)
        if(n % i == 0) return false;
    return true;

Miller-Rabin演算法:

這是一種隨機性素數判定演算法,也就是說,答案可能出錯,但是可能性極小。

先是講兩個定理:

費馬小定理:
對於一個質數p,取任意整數a,滿足gcd(p,a)=1,則有

ap11(modp)

二次探測定理:
對於0

<x<p,若p是素數,則方程:

x21(modp)
的解為:
x1=1,x2=p1

因為費馬小定理的逆命題不成立,而否逆命題成立,所以我們可以利用一下一點:
對於任意整數a<p,不滿足ap11(modp),則p為合數。

所以我們可以不斷在區間[2,p1]範圍內隨機取a,並進行判定。在s次判定不為合數之後,我們就可以說這個數是質數。

但是這還不夠精確,我們可以先把p1分解成2t×u(u{x|x=2k+1,kN})的形式,然後令x[0]=aumodp,,那麼將x[0]平方t次就是(au)2tmodp的值,我們設x[i]x[0]平方i次的值,根據二次探測定理,若x

[i]等於1,則x[i1]等於1或p-1,不滿足則p為合數。

注意以上操作中所有的形如abmodp的式子都要用快速冪運算,當n比較大時,形如a×bmodp的式子也要使用分治的思想來計算。

這就是Miller-Rabin演算法的主要內容。

時間複雜度:考慮常數後為O(slog3n)

程式碼如下:

const int MAXN = 65;
long long n, x[MAXN];

long long multi(long long a, long long b, long long p) {
    long long ans = 0;
    while(b) {
        if(b&1LL) ans = (ans+a)%p;
        a = (a+a)%p;
        b >>= 1;
    }
    return ans;
}

long long qpow(long long a, long long b, long long p) {
    long long ans = 1;
    while(b) {
        if(b&1LL) ans = multi(ans, a, p);
        a = multi(a, a, p);
        b >>= 1;
    }
    return ans;
}

bool Miller_Rabin(long long n) {
    if(n == 2) return true;
    int s = 20, i, t = 0;
    long long u = n-1;
    while(!(u & 1)) {
        t++;
        u >>= 1;
    }
    while(s--) {
        long long a = rand()%(n-2)+2;
        x[0] = qpow(a, u, n);
        for(i = 1; i <= t; i++) {
            x[i] = multi(x[i-1], x[i-1], n);
            if(x[i] == 1 && x[i-1] != 1 && x[i-1] != n-1) return false;
        }
        if(x[t] != 1) return false;
    }
    return true;
}