[学习笔记]Miller-Rabin素数检测

[学习笔记]Miller-Rabin素数检测

一.什么是Miller-Rabin

​ miller-rabin是一个用来检验一个数是不是素数的算法,速度非常的快,\(O(\log^2n)\)(加了快速加法)

二.费马小定理

​ 对于素数p,有
\[ a^p\equiv a\;(mod\; p) \]
​ 这是费马小定理的基本形式。可以变形成为\(a^{p-1}\equiv1(mod\;p)\)。对于费马小定理来说,大多数时候满足这个式子的一个自然数是一个质数,当然有满足却不是质数的情况。并且不满足他的一定不是质数,这是Miller-Rain算法的基本原理。也就是说,当我们用多个底数a检验一个自然数,发现都满足费马小定理,我们就大约可以认定他是一个质数。

​ 对于这样的一类数p(以561为代表):\(\forall\;a\in Z,a^{p-1}\equiv1(mod\;p)\),我们称它为Carmichael数,普通的Miller-Rabin是会将他们误判为素数的。

三.二次探测定理

​ 对于一个奇素数(除2以外的素数)来说,一个方程\(x^2\equiv1(mod\;p)\)的解为\(x\equiv1(mod\;p)\)\(x\equiv p-1(mod\;p)\)

​ 证:
\[ \begin{align} x^2\equiv1(mod\;p)\\ x^2-1\equiv0(mod\;p)\\ (x+1)(x-1)\equiv0(mod\;p) \end{align} \]

​ 于是对于一个p-1为偶数的指数来说,我们就先把它用二次探测定理做一遍。令\(u=\frac{p-1}{2}\),对\(a^u\equiv1(mod\;p)\),\(a^u\equiv p-1(mod\;p)\),进行判定。

四.后记

​ 以上的两种方法结合起来应该就可以进行正确的检验素数,但然也可以先把几个常用的素数:2,3,5...17等先判定一遍以此来减小出错概率(笔者还没有测过)

​ 对于比较大的数据,乘法(x^2)可能会出现溢出,于是要打一个快速加来模仿乘法。

五.代码

#define m_for(i,a,b) for(int i=(a);i<=(b);++i)
#define ll long long
const int times=10;
ll multi(ll a,ll b,ll m)
{
    ll ans=0%m;
    while(b)
    {
        if(b&1)ans=(ans+a)%m,b--;
        b >>= 1;
        a=(a+a)%m;
    }
    return ans;
}
ll KSM(ll a,ll b,ll m)
{
    ll ans=1%m;
    while(b)
    {
        if(b&1)ans=multi(ans, a, m),b--;
        b>>=1;
        a=multi(a,a,m);
    }
    return ans;
}
inline bool Miller_Rabin(ll p){
    if(p<=2)return p==2;
    if(!(p&1))return 0;
    ll u=p-1;
    int power=0;
    while(!(u&1))u>>=1,power++;
    m_for(i,1,times){
        ll a=rand()%(p-2)+2,x=KSM(a,u,p),y;
        for(int i=1;i<=power;++i,x=y){
            if((y=multi(x,x,p))==1&&x!=1&&x!=p-1)return 0;
        }
        if(x!=1)return 0;
    }
    return 1;
}

猜你喜欢

转载自www.cnblogs.com/clockwhite/p/12148877.html