【数学】MillerRabin算法
原理
目标:检测某个较大的正整数 \(n\) 是否为质数。
证明:
若 \(n \leq 2\) 则直接给出结果。否则,若 \(n\) 为偶数,也直接给出结果。
否则,假设 \(n\) 为奇质数,显然 \(n-1\) 为偶数,可以写成 \(2^sd\) 的形式,其中 \(s\) 是正整数,而 \(d\) 是奇数。则对于任意 \(a\) 和 \(0\leq r\leq s-1\) ,必定满足以下两种形式的一种:
\(a^d\equiv 1 \pmod{n}\) 或 \(a^{2^rd}\equiv -1 \pmod{n}\) 。
因为,由于费马小定理,若 \(n\) 为质数,则 \(a^{n-1}\equiv 1 \pmod{n}\) (反之不成立)。
代码
ll qmul(ll a, ll b, ll mod) {
return (__int128)a * b % mod;
}
ll qpow(ll a, ll b, ll mod) {
if(a >= mod)
a %= mod;
ll res = 1;
while(b) {
if(b & 1)
res = qmul(res, a, mod);
a = qmul(a, a, mod);
b >>= 1;
}
return res;
}
namespace MillerRabin {
// private
bool MR(ll n, ll p) {
for(ll k = n - 1; k; k >>= 1) {
ll t = qpow(p, k, n);
if(t != 1 && t != n - 1)
return false;
if((k & 1) == 1 || t == n - 1)
// probably true
return true;
}
// probably true
return true;
}
// public
bool isPrime(ll n) {
if(n <= 1)
return false;
if(n <= 3)
return true;
if(!(n & 1))
return false;
static int basePrime[5] = {2, 3, 7, 61, 24251};
for(int i = 1; i <= 5; ++i) {
if(n == basePrime[i - 1])
return true;
if(!MR(n, basePrime[i - 1]))
return false;
}
if(n == 46856248255981LL)
return false;
// probably true
return true;
}
}
using namespace MillerRabin;
check函数的意图是用质数p作为基检查x是否为质数。
首先排除掉相等的情况,然后排除掉x已经有p作为质数的情况。然后后续p只会出现在快速幂中,所以先进行一次取模。先用费马小定理确定x不是质数。