Miller_Rabin :)

Miller_Rabin:读作米勒罗宾。知道这个名字是学习这个算法的唯一难点。

怎么判断一个数p是否是素数???

最容易想到的就是去判断从2到\sqrt{p}的整数中,有没有可以整除p的数。(因为素数的定义就是从只有1和它本身是它自己的因数啊)。

但是很明显,这种方法需要的时间是O(\sqrt{n})的,所以在遇到一些比较大的数字的时候,这种方法就很麻瓜了。

1.费马小定理:当a与p互质的时候,且p是素数的时候,a^{^{p-1}}\equiv 1mod p,例如:a是4,p是7.

那么,a的 6(7-1)次方,也就是4096,再对7取余,结果就是1.

那么反过来,如果当a的p-1次方再对p取余的结果是1,那么是否就说明p是素数呢???很可惜,并不是。还存在着一些数(伪素数)也可以有这种性质,但是这确实可以成为判断素数的一种方法,只不过不准确而已。接下来就可以看到它的用处2.

2.二次探测定理:当p是素数的时候,x是小于p的正整数,并且x^{2}\equiv 1mod p,那么x的值就

只能是1或者p-1.这是一个必要条件!!!!就是说p是素数的时候,x只能是1或者p-1.(我没有说反过来也成立,比如8^2%9=64%9=1),是不是把费马小定理和二次探测定理结合就可以完全判断了呢??很可惜,也不是。

简单证明:把1移动到左边,x^2-1=0 mod p.

即 (x+1)*(x-1)=0 mod p.很明显,x=-1,或者1,(注:这里的1,和-1是在mod p意义下的1和-1,x=-1,其实x=p-1)

怎么利用这个性质判断p是否为素数??

令a=x^2,那么可以知道,要满足上述式子,a开方的值一定会是p-1,或者是1。

结合上面的费马小定理,也就给了一个判定的思路,我们随机的选取小于p的值b,去计算b^(p-1) mod p,如果p是素数,怎么结果必然是1.那b^{(p-1)-1}的值就必然会是1,或者p-1了。如果b^{(p-1)-1}的值是1,那不就是又去判断b^{(p-1)-2}的值是不是1或者p-1.  直到没办法可以开平方为止。实际代码过程有一些出入。代码实现是去找最终不能开方的次方,再不断的平方的。没说清??不慌,看了代码就懂了。

以上就是大概的判断过程,上面也说了,这种判断方法并不可靠,根据那些厉害的人推出的错误期望:每一次有25%的几率是错的,具体证明我不证了(好吧,我证明不来,也没看到一个正儿八经的证明),也就是通过了所有的测试,但是实际上p是一个合数。

25%的错误率很明显太高了,那就多选几次来测试不就可以提高准确率了,比如,选10次判断错误的概率就是:(0.25)^10,也就是百万分之一了,选15次错误的几率就是十亿分之一了,一生中被雷劈的概率也就是1.2万分之一,破记录的强力球头奖也就2.92亿分之一,被陨石砸中的记录是7亿分之一,所以,这算法还是很可靠的。

时间复杂度???把代码看懂了就知道了。(其实写这个是为了后面的泼辣肉算法)。

最后:代码(有些细节地方需要自己理解,只写这么多了,再写就让人烦了)。

#include<bits/stdc++.h>
using namespace std;
long long  int mod;
long long int quick_pow(long long int n,long long int base)
{
    long long int ans=1;
    while(n)
    {
        if(n&1)
            ans*=base,ans%=mod;
        n>>=1;
        base*=base;
        base%=mod;
    }
    return ans;
}
bool Miller_Rabin(long long int val,long long int a)
{
    if(val==a)
        return true;
    if(val%a==0||val<2)
        return false;
    long long int u=val-1;
    int k=0;
    while(!(u&1))
    {
        u>>=1;
        ++k;
    }
    long long int temp=quick_pow(u,a)%mod;
    if(temp==1||temp==val-1)
        return true;
    for(int i=1;i<=k;++i)
    {
        temp=temp*temp%mod;
        if(temp==val-1)
            return true;
    }
    return false;
}
int main()
{
    long long int n;
    long long int a;
    cin>>n;
    mod=n;
    srand(time(0));
    bool flag=true;
    for(int i=0;i<15&&n!=2;++i)
    {
        a=rand()%(n-2)+2;
        if(!Miller_Rabin(n,a))
        {
            flag=false;
            break;
        }
    }
    if(flag)
        cout<<"n is prime"<<endl;
    else
        cout<<"n not's prime"<<endl;
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值