原理
目标:检测某个较大的正整数 (n) 是否为质数。
证明:
若 (n leq 2) 则直接给出结果。否则,若 (n) 为偶数,也直接给出结果。
否则,假设 (n) 为奇质数,显然 (n-1) 为偶数,可以写成 (2^sd) 的形式,其中 (s) 是正整数,而 (d) 是奇数。则对于任意 (a) 和 (0leq rleq s-1) ,必定满足以下两种形式的一种:
(a^dequiv 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不是质数。