Miller-Rabin素数测试

    如果要判断一个比较大的数是否为素数,那么此时传统的试除法和筛法显然不再适用,我们引入一种概率型素数判定方法——Miller-Rabin素数测试。

    由费马小定理可以知道,若n是素数且a是整数,则满足a^n≡a(mod n).若存在a不满足上式,那么n是合数。由此我们定义伪素数:令a是一正整数,若n是合数且满足a^n≡a(mod n),那么n称为以a为基的伪素数。

    Miller-Rabin素数测试基于费马小定理:假如n是素数且gcd(a,n)=1,那么a^(n-1)≡1(mod n).如果a^(n-1)≡1(mod n)(a为任意小于n的正整数),则可近似认为n为素数,取多个底进行试验,次数越多,n为素数的概率越大。

    定义卡迈克尔数:一个合数n,若对于所有满足gcd(b,n)=1的正整数b都有b^(n-1)≡1(mod n)成立,则称之为卡迈克尔数.

    为了排除卡迈克尔数导致Miller-Rabin测试出现错误,我们引进二次探测定理:如果p是素数且0<x<p,则方程x^2%p=1的解为x=1或x=p-1.


改进后的Miller-Rabin素数测试实现代码如下:

#include <cstdio>
#include <iostream>
#include <cstdlib>
using namespace std;
#define N 10
typedef long long LL;
LL random(LL n)
{
    return (LL)((double)rand()/RAND_MAX*n+0.5);
}
LL multi(LL a,LL b,LL m) //计算a*b%m
{
    LL ret=0;
    while(b)
    {
        if(b&1) ret=(ret+a)%m;
        b>>=1;
        a=(a<<1)%m;
    }
    return ret;
}
LL quick_mod(LL a,LL b,LL m) //计算a^b%m
{
    LL ans=1;
    while(b)
    {
        if(b&1)
        {
            ans=multi(ans,a,m);
            b--;
        }
        b>>=1;
        a=multi(a,a,m);
    }
    return ans;
}
bool miller_rabin(LL n)
{
    if(n==2) return true;
    if(n<2||!(n&1)) return false;
    LL m=n-1;
    int k=0;
    while((m&1)==0)
    {
        k++;
        m>>=1;
    }
    for(int i=0; i<N; i++)
    {
        LL a=rand()%(n - 1)+1;
        LL x=quick_mod(a,m,n);
        LL y=0;
        for(int j=0;j<k;j++)
        {
            y=multi(x,x,n);
            if(y==1&&x!=1&&x!=n-1) return false;
            x=y;
        }
        if(y!=1) return false;
    }
    return true;
}
int main()
{
    LL n;
    while(cin>>n)
      if(miller_rabin(n)) puts("yes");
      else puts("no");
    return 0;
}


你可能感兴趣的:(Miller-Rabin素数测试)