【数论基础】素数判定和Miller Rabin算法

判断正整数p是否是素数

方法一 朴素的判定   

方法二 线筛 

对于大整数(>1e9),可以优化

方法三 利用费马小定理

假如p是质数,且gcd(a,p)=1,那么 a^(p-1) ≡1(mod p)。
即:假如a是整数,p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒等于1。
我们这样写:a*a^(p-2) ≡1(mod p)
根据定义,a^(p-2)就是a (模p)的逆元
 
那么反过来,随机整数a能使p满足a^(p-1) ≡1(mod p)的话,那么p就是质数?
当然不是,虽然很大可能是,但是会有特殊的存在。
如2^340≡1(mod 341),但341=31*11
具体来说,特殊的数是费马伪素数和卡迈克尔数,这里不介绍了
 
方法四 二次探测定理
对于任意素数p, 满足方程
有唯一解 x=1||p-1
证明
 
方法五 Miller Rabin算法
逆用费马小定理加上二次探测,就得到了 Miller Rabin 算法。
Miller Rabin 算法有一定的出错概率,出错的情况一定是将合数判定为素数,且出错概率极低
 
对于一个奇素数(偶素数只有2嘛),显然p-1是偶数
则有推导过程如下:
 
所以算法实现过程有两步:
1.枚举k,对于每一个k,检验是否满足二次探测定理(即上面的最后一步)
2.再检验是否满足费马小定理
 
对于任意一个p,如果通过了算法检验,则它不是素数的概率是25%
那么k轮之后,p不是素数的概率就是0.25^k,就很小了
一般8-10轮就差不多了
那么对于a的选择,可以选前面几个质数:2,3,5,7,11等,也可以用随机数
时间复杂度一般是,k为测试的轮数
//里面有龟速乘和快速幂,防越界
inline int slow_mult(int a,int b,int mod){
    int ans=0;
    while(b){
        if(b&1)    ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}

inline int quick_pow(int a,int b,int mod){
    int ans=1;
    while(b){
        if(b&1)    ans=slow_mult(ans,a,mod);
        a=slow_mult(a,a,mod);
        b>>=1;
    }
    return ans;
}

inline bool Miller_Rabin(int p){
    if(p==2)    return true;
    if(p==1||p%2==0)    return false;
    int u=p-1,t=0;
    while(u%2==0)    u/=2,t++;    
    for(int i=0;i<=9;i++){//我测了十次
        int a=rand()%(p-1)+1;
        int x=quick_pow(a,u,p);
        if(x==1)    continue;
        for(int j=1;j<=t;j++){
            int y=slow_mult(x,x,p);
            if(y==1 && x!=1 && x!=p-1)    return false;//二次探测定理
            x=y;//递推求2的幂 
        }
        if(x!=1)    return false;//费马小定理 
    }
    return true;
}

 

posted @ 2020-05-01 19:36  初学者Ming  阅读(406)  评论(0编辑  收藏  举报