miller_rabbin 算法

miller_rabbin算法

这是一个质数判断算法,它采用随机算法能够在很短的时间里判断一个数是否是质数。
首先,根据费马定理,若 p p p为质数,取a<p,则 a p − 1 % p = 1 a^{p-1}\%p=1 ap1%p=1.但反过来则不成立。
因为有一类数——卡迈克尔数,它不是质数,但也满足 a p − 1 % p = 1 a^{p-1}\%p=1 ap1%p=1
如何将卡迈克尔数甄别出来。我们要用到二次探测方法。
p p p为我们要判断的数,将 p − 1 p-1 p1分解为 2 r ∗ k 2^r*k 2rk,则有 a p − 1 = ( a k ) 2 r a^{p-1}=(a^{k})^{2^r} ap1=(ak)2r
则我们可以先求出 a k a^k ak,然后将其不断平方,并模p。如果第一次出现模 p p p的值为1,那么检测上一次的值是否为 − 1 -1 1,如果是,则没有毛病;否则可以断定不是质数。
证明:
y 2 % p = 1 y^2\%p=1 y2%p=1
则等价于: y 2 − 1 = k ∗ p y^2-1=k*p y21=kp
等价于: ( y − 1 ) ∗ ( y + 1 ) = k ∗ p (y-1)*(y+1)=k*p (y1)(y+1)=kp
如果 p p p是质数,则 { y − 1 = 0 y + 1 = p \begin{cases} y-1=0 \\ y+1=p \\ \end{cases} {y1=0y+1=p
即y的值只能为 1 1 1 p − 1 p-1 p1
所以,如果 y ≠ 1 y\neq 1 y=1 y ≠ p − 1 y\neq p-1 y=p1,则可以断定 p p p不是质数。
而如果做r次平方,模 p p p的值都不为1,则 p p p显然不是质数了。
那如果在平方r次的过程中,最后的结果为1了。而且第一次结果为1时,之前的结果为-1。是不是就能保证 p p p是质数呢?也不能百分百地肯定。但是相比于仅通过费马定理来判断,它更严格一些了。这种方法称为二次检测。
于是,我们可以多次选择 a a a,如果选了许多 a a a来做上述的操作,都不能判断出 p p p是合数,则 p p p多半就是一个质数了。
miller_rabbin算法是一个随机算法,并不能完全保证结果准确,但是出错的概率非常小。我们取a的次数越多,出错的概率越小。一般情况下,取20~30次a,正确率已经可以达到99.9999999%了。

FZU1649
给出若干整数,判断它是否是素数。
参考代码如下:

#include<iostream>
#include<cstring>
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL unsigned long long int
LL n,k;
int t,r;
bool notprime;
LL ksc(LL a,LL b,LL p)
{
    LL res=0;
    while(b)
    {
        if(b&1)res=res+a;
        a=a+a;
        if(res>=p)res-=p;
        if(a>=p)a-=p;
        b>>=1;
    }
    return res;
}
LL ksm(LL a,LL b,LL p)
{
    LL res=1;
    while(b)
    {
        if(b&1)res=ksc(res,a,p);
        a=ksc(a,a,p);
        b>>=1;
    }
    return res;
}
int main()
{
    srand(time(NULL));
    while(scanf("%I64d",&n)!=-1)
    {
     if(n==2||n==3)
    {
         printf("It is a prime number.\n");
         continue;
    }
    else
    {
        if(n==1||n&1==0)
        {
            printf("It is not a prime number.\n");
            continue;
        }   
    }
    
    r=0;
    k=n-1;
    while(!(k&1))
    {
        r++;
        k>>=1;
    }
    int t=20;
    LL res=1,lastres=0;
    notprime=0;
    for(int id=0;id<=10;id++)
    {
        res=rand()%(n-1)+1;
        res=ksm(res,k,n);
        if(res==1)
        continue;
        lastres=res;
        for(int i=0;i<r;i++)
        {
            res=ksc(res,res,n);
            if(res==1)
            {
                if(lastres!=n-1) notprime=1;
               break;
            }
            lastres=res;
        }
        if(notprime==1)break;
        if(res!=1)
        {
            notprime=1;
            break;
        }
    }
    if(notprime==1)
        printf("It is not a prime number.\n");
    else 
        printf("It is a prime number.\n");
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值