Miller Rabin
概要
一种随机化判定质数方法。
根据执行次数不断增加,其正确率可以快速增长,以达到我们想要的目的。
前置知识
二次探测定理
对于质数 \(p\),若有 \(a^2\equiv 1\pmod p\),那么 \(a\equiv \pm 1\pmod p\)。
证明:
\[a^2-1\equiv 0\pmod p
\]
\[(a+1)(a-1)\equiv 0\pmod p
\]
因为 \(p\) 是质数,由唯一分解可得:
\[a\equiv \pm 1
\]
算法流程
将 \(p-1\) 拆分成 \(2^k\times t\) 的形式,然后 随机 rand 一个 \(a\),计算出 \(a^t\)。
每次比较 \(a^{2^i\times t}\pmod p\) 和 \(a^{2^{i+1}\times t}\pmod p,i\in[0,k)\) 是否符合前文的二次探测定理。
若出现了一项不符合,即可判定 \(p\) 为合数。
那么对于当前 rand 出来的这个 \(a\),有 一定的概率 可以判断出来 \(p\) 是合数(如果是的话)。
经过一次 \(p\) 不是质数却未被判出的概率似乎最大为 \(\frac{1}{4}\),具体的我也算不来。
那么做个七八次就好了,非常的稳妥。
可以用 \(2,3,5,7,11,13,17,19\) 这几个质数作为 \(a\),也可以 rand 几个质数,看个人习惯。
代码实现
主要是调用的函数部分。
bool pri[20];
vector<int>prime;
inline void init()
{
for(int i=2;i<20;i++){if(!pri[i])prime.push_back(i);for(auto j:prime){int now=i*j;if(now>=20)break;pri[now]=true;if(i%j==0)break;}}
pri[1]=true;srand(time(0));return;
}
inline bool Miller_Robin(LL n,int a)
{
LL t=n-1,lst;int k=0;for(;!(t&1);t>>=1)k++;lst=t=ksm(a,t,n);
for(int i=1;i<=k;i++){t=prpr(t,t,n);if(t==1&&lst!=1&&lst!=n-1)return false;lst=t;}return lst==1;
}
inline bool ifprime(LL n){if(n<20)return !pri[n];for(auto j:prime)if(!Miller_Robin(n,j))return false;return true;}
$$\texttt{Dirty Deeds Done Dirt Cheap}$$