Miller_Rabin--大素数判定算法

一篇很好的Miller_Rabin讲解博客 费马小定理:对于一个素数p,对于任意整数a,若gcd(a,b)=1,则ap11(modp) 如果要判断p是不是素数,就每次在[2,p1]中随机x,如果xp11则p不是素数。 但这还不够精确。 二次探测定理,对于一个奇素数p,如果a21(modp),则a1(modp)ap1(modp) 我们可以把p1分解成2tu,然后令x[0]=aumodpx[i]=x[i1]2modp,则x[t]=ap1如果x[i]=1,则x[i1]一定等于1p1,否则p不为素数。如果x[t]1p同样不为素数。

当然2要特判。 每次判断错误率为14,判断s次后错误率为(14)s。 时间复杂度O(slog3n) 如果p大,则乘法要用"类快速幂"计算。

long long x;
long long f[128];
long long bigrand(long long l,long long r){
    return (((long long)rand()<<31)+rand())%(r-l+1)+l;
}
long long mul(long long a,long long b,long long p){
    long long c=0;
    while(b){
        if(b&1)c=(c+a)%p;
        a=(a+a)%p;
        b>>=1;
    }
    return c;
}
long long fpm(long long a,long long b,long long p){
    long long c=1;
    while(b){
        if(b&1)c=mul(c,a,p);
        a=mul(a,a,p);
        b>>=1;
    }
    return c;
}
long long Miller_Rabin(long long x){
    long long y=x-1,t=0;
    if(x==2)return 1;
    while(!(y&1)){y>>=1;++t;}
    up(i,1,128){
        long long k=bigrand(2,x-1);
        f[0]=fpm(k,y,x);

        up(j,1,t){
            f[j]=mul(f[j-1],f[j-1],x);
            if(f[j]==1&&f[j-1]!=1&&f[j-1]!=x-1){
                return 0;
            }
        }
        if(f[t]!=1)return 0;
    }
    return 1;
}
int main(){
    long long n;
    srand(2333);
    n=read();
    while(n){
        --n;
        x=read();
        if(Miller_Rabin(x)){
            printf("Yes\n");
        }
        else printf("No\n");

    }
    return 0;
}