Miller_Rabin素数测验

1.背景
数论学家利用费马小定理研究出了多种素数测试办法,Miller-Rabbin 素数测试算法是其中较快的一种。
二次探测定理:如果 p 是素数,且 0<x<p ,则方程 x21(mod p) 的解为 1 p1

2.过程
(1)计算奇数M,使得N=2^r * M + 1;
(2)选择随机数A < N;
(3)对于任意i < r,若A^(2^i*M) mod N = N - 1,则N通过随机数A的测试;
(4)或者,若A^M mod N = 1,则N通过随机数A的测试;
(5)让A取不同的值对N进行行多次测试(一般要求5~10次,有较高要求的话可以进行20~30次),若全部通过则判定N为素数;

3.概率计算
若N通过一次测试,则N不是素数的概率为25%;
若N通过 t 次测试,则N不是素数的概率为1/( 4 ^ t );
事实上,当 t = 5 时,N不是素数的概率已为1/128,已经大于99.99%。
在实际运用中,可首先用300~500个小素数对N进行测试,以提高测试通过的概率与算法的速度。在随机生成的素数中,选取的随机数最好让 r = 0,则可以省去步骤(3)的操作,进一步减少判定时间。

4.代码

// 18位素数:154590409516822759  
// 19位素数:2305843009213693951 (梅森素数)  
// 19位素数:4384957924686954497  
LL prime[6] = {2, 3, 5, 233, 331};  
const int time = 5;
LL qmul(LL x, LL y, LL mod) { // 乘法防止溢出, 如果p * p不爆LL的话可以直接乘; O(1)乘法或者转化成二进制加法    
    return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;  
    /* 
    LL ret = 0; 
    while(y) { 
        if(y & 1) 
            ret = (ret + x) % mod; 
        x = x * 2 % mod; 
        y >>= 1; 
    } 
    return ret; 
    */  
}  
LL qpow(LL a, LL n, LL mod) {  
    LL ret = 1;  
    while(n) {  
        if(n & 1) ret = qmul(ret, a, mod);  
        a = qmul(a, a, mod);  
        n >>= 1;  
    }  
    return ret;  
}  
bool Miller_Rabin(LL p) {  
    if(p < 2) return 0;  
    if(p != 2 && p % 2 == 0) return 0;  
    LL s = p - 1;  
    while(! (s & 1)) s >>= 1;  
    for(int i = 0; i < 5; ++i) {  
        if(p == prime[i]) return 1;  
        LL t = s, m = qpow(prime[i], s, p);  
        while(t != p - 1 && m != 1 && m != p - 1) {  
            m = qmul(m, m, p);  
            t <<= 1;  
        }  
        if(m != p - 1 && !(t & 1)) return 0;  
    }  
    return 1;  
}  


阅读全文

你可能感兴趣的:(数论)