Miller Rabin算法学习笔记
\(Miller\ Rabin\)算法学习笔记
\(Miller\ Rabin\)是一种快速的随机化的素数测定方法。
它基于以下定理
二次探测定理:若\(x^2\equiv1\pmod p\),则\(x\equiv±1\pmod p\)
证明大概就是\((x-1)(x+1)\equiv0\pmod p\)
然后我们选取一个底\(a\),设你当前要判断的数为\(x\)
初始我们判断\(a^{x-1}\)是否为\(1\),不是判定\(x\)为合数
然后判断\(a^{\frac {x-1}2}\)是否为\(1\)或\(p-1\),不是判定\(x\)为合数
如此反复,直到指数是奇数或余数为\(p-1\)为止。
于是此时我们就认为\(x\)通过了基于\(a\)为底的测试。
一次测试错误率大概是\(\frac 14\)
多次测试的错误率一般认为是\(\frac 1{4^x}\)的,可以接受。
代码就直接模拟就可以了。
\(upd:\)我们可以优化一下,从后往前检测,如果其中有一个通过了二次探测,就判定\(x\)是质数。
优化后代码:
/*bool Test(ll a,ll x)
{
if(a>=x)return 1;
ll ret=qpow(a,x-1,x),s=x^1;
while(ret==1&&!(s&1))s>>=1,ret=qpow(a,s,x);
return ret==1||ret==(x^1);
}*/
bool Test(ll a,ll x)
{
if(a>=x)return 1;
ll ret,s=x^1;
int p=__builtin_ctzll(s);
ret=qpow(a,s>>p,x);
if(ret==1||ret==(x^1))return 1;
while(p--&&ret!=(x^1))ret=mul(ret,ret,x);
return p>=0;
}
int lst[]={2,3,5,7,11,13,17,19,23};
bool Miller_Rabin(ll x)
{
if(x==1)return 0;
if(x==2)return 1;
if(x&1)
{
for(int i=0;i<9;++i)if(!Test(lst[i],x))return 0;
return 1;
}
return 0;
}
\(2st\ upd:\)在一般是选\(2,3,7,61,24251\)为基底,此时在\(1e16\)内只有\(46856248255981\)是强伪素数。