MR素性探测
简介
MR算法全称是Miller-Rabin测试,是一个非确定的算法,用于判断一个数是否是质数.虽然是一个非确定的算法,但是只要巧妙地选取参数,在一定范围内就是一个确定性的算法.
前置条件:费马小定理 1 ≡ a^(p-1) (mod p)
Miller和Rabin两个人的工作让Fermat素性测试迈出了革命性的一步,建立了传说中的Miller-Rabin素性测试算法。 新的测试基于下面的定理(
二次探测定理
):如果p是素数,x是小于p的正整数,且x^2 mod p = 1
,那么要么x=1,要么x=p-1。这是显然的,因为x^2 mod p = 1相当于p能整除x^2-1,也即p能整除(x+1)(x-1)
。由于p是素数,那么只可能是x-1
能被p整除(此时x=1)或x+1
能被p整除(此时 x=p-1)。
这就 是Miller-Rabin素性测试的方法。不断地提取指数n-1中的因子2,把n-1表示成
d*2^r(其中d是一个奇数)
。那么我们需要计算的东西就 变成了a的d*2^r次方除以n的余数
。于是,a^(d * 2^(r-1))
要么等于1,要么等于n-1。如果a^(d * 2^(r-1))
等于1,定理继续适用于a^(d * 2^(r-2))
,这样不断开方开下去,直到对于某个i满足a^(d * 2^i) mod n = n-1或者最后指数中的2用完了得到的a^d mod n=1或n-1。这样,Fermat小定理加强为如下形式:
尽可能提取因子2, 把n-1表示成d*2^r,如果n是一个素数,那么或者a^d mod n=1,或者存在某个i使得a^(d*2^i) mod n=n-1 ( 0<=i<r )
(注意i可以等于0,这就把a^d mod n=n-1
的情况统一到后面去了)
关于正确性
如果你每次都用前7个素数(
2, 3, 5, 7, 11, 13和17
)进行测试,所有不超过341 550 071 728 320
(即3.4e14)的数都是正确的。如果选用2, 3, 7, 61和24251
作为底数,那么10^16内唯一的强伪素数为46 856 248 255 981
(即4.6e13)。
注意是当取模为1时才能继续降幂取模,取模为N-1时算法终止(但是之后的算法实际上不是这么死板地实现的).
模板
ll Quick_Multiply(ll a, ll b, ll c) //快速积(和快速幂差不多)
{
long long ans = 0, res = a;
while (b) {
if (b & 1)
ans = (ans + res) % c;
res = (res + res) % c;
b >>= 1;
}
return ans;
}
ll Quick_Power(ll a, ll b, ll c) //快速幂,这里就不赘述了
{
ll ans = 1ll, res = a;
while (b) {
if (b & 1)
ans = Quick_Multiply(ans, res, c);
res = Quick_Multiply(res, res, c);
b >>= 1;
}
return ans;
}
bool Miller_Rabin(ll n, int a, ll d) //判断素数
{
if (n