Miller-Rabin(素数测试算法)

【作用】

一般素数判定方法有试除法和Miller-Rabin。试除法枚举2-√n,时间复杂度为O(√n) , 一旦n特别大,就不适合用试除法进行判定。

这时候我们可以对其进行 Miller-Rabin 素数测试,可以大概率测出其是否为素数。

【两个基础理论】

(1):费马小定理:当p为质数时,有ap-1≡1(mod p).注意逆命题是假命题,比如卡迈克尔(Carmichael)数。

对于合数满足费马小定理的数叫伪素数,

(2):二次测探:如果p是一个素数,0<x<p,则方程x2≡1(mod p)的解为x = 1 或 x = p - 1.

 

 

 (1)对于一些常见的素数和非素数 可以直接判断。

(2)设要测试的数为 x,我们取一个较小的质数 a,设 s,t,满足 2s * t = x - 1(其中 t 是奇数)。

(3)我们先算出 a^t,然后不断地平方并且进行二次探测(进行 s 次)。

(4)最后我们根据费马小定律,如果最后不满足费马小定理 ,则说明 x 为合数。

(5)多次取不同的 a 进行 Miller-Rabin 素数测试,这样可以使正确性更高

https://blog.csdn.net/forever_dreams/article/details/82314237

https://www.cnblogs.com/Antigonae/p/10226580.html

int quickmul(int a , int b , int m){
    return  ((a * b - (ll)(long double)(a/m*b) * m)+m)%m ;
}

int quickpow(int a , int b , int m){
    int ans = 1 ;
    while(b){
        if(b&1) ans = quickmul(ans , a , m) ;
        b >>= 1 ;
        a = quickmul(a , a , m);
    }
    return ans ;
}

bool Miller_Rabin(int n){
    if(n == 46856248255981ll || n < 2) return false;
    if(n == 2 || n == 3 || n == 7 || n == 61 || n == 24251) return true;
    if(!(n&1) || !(n%3) || !(n%61) || !(n%24251)) return false;
    int m = n - 1 , k = 0 ;
    while(!(m&1)) k++ , m>>=1 ;// 分解2^s * t = n - 1
    rep(i , 1 , 20){
        int a = rand() % (n - 1) + 1 , x =  quickpow(a , m , n) , y;
        rep(j , 1 , k){
            y = quickmul(x , x , n);
            if(y == 1 && x != 1 && x != n - 1) return false;//二次测探
            x = y ;
        }
        if(y != 1) return false;//费马小定理
    }
    return true;
}

void solve(){
    int x ;
    cin >> x ;
    if(Miller_Rabin(x)) cout << "Yes" << endl;
    else cout << "No" << endl;
}

 

posted @ 2020-03-06 21:53  无名菜鸟1  阅读(1148)  评论(0编辑  收藏  举报