如同标题所述,Miller_Rabin 是用来测试一个数是否为素数的算法。然而,Miller_Rabin是有缺陷的,这就是它单次执行所得的结果并不完全正确,不过我们可以将这个算法多执行几次来让它的正确率趋近于 100% 100 % 。
Fetmat F e t m a t 小定理:若 p p 为素数, a a 为正整数,且 (a,p)=1 ( a , p ) = 1 ,则 ap−1≡1(modp) a p − 1 ≡ 1 ( mod p ) .
Fetmat F e t m a t 小定理的逆命题不是真命题,但是满足两个条件的 p p 有很大概率是素数,所以多测试几次可以提高判断准确程度。
二次探测定理:如果 p p 是一个素数, 0<x<p 0 < x < p , 则方程 x2≡1(modp) x 2 ≡ 1 ( mod p ) 的解为 x=1 x = 1 或 x=p−1 x = p − 1 .
同样也是逆用这个定理,若 x2≡1(modp) x 2 ≡ 1 ( mod p ) 且 x≠1 x ≠ 1 , x≠p−1 x ≠ p − 1 ,则 p p 一定不是质数,与 Fetmat F e t m a t 小定理结合提高准确度。
快速幂。
由于Miller_Rabin是概率算法,所以要多次选取素数保证正确程度, int i n t 范围内 使用 2,3,61 2 , 3 , 61 这三个数即可。实在担心的话取 2,3,7,19,61,24251 2 , 3 , 7 , 19 , 61 , 24251 ,准确性就相当高了。
\\随机
LL FastPower(LL a, LL p, LL k) {
LL ans = 1;
while (p) {
if (p & 1) ans = (ans * a) % k;
a = (a * a) % k;
p >>= 1;
}
return ans;
}
bool judge(LL a, LL n, LL m, LL r) {
LL x = FastPower(a, m, n);
if (x == 1 || x == n - 1) return true;
while (r--) {
x = (x * x) % n;
if (x == n - 1) return true;
}
return false;
}
bool Miller_Rabin(LL n) {
if (n == 2) return true;
if (n == 1 || !(n & 1)) return false;
LL m = n - 1, r = 0;
while (!(m & 1)) {
r++;
m >>= 1;
}
for (int i = 0; i < 10; i++) {
int a = rand() % (n - 1) + 1;
if (!judge(a, n, m, r))
return false;
}
return true;
}
\\指定
const int len = 6;
const LL base[len] = {2, 3, 7, 19, 61, 24251};
LL FastPower(LL a, LL p, LL k) {
LL ans = 1;
while (p) {
if (p & 1) ans = (ans * a) % k;
a = (a * a) % k;
p >>= 1;
}
return ans;
}
bool judge(LL a, LL n, LL m, LL r) {
LL x = FastPower(a, m, n);
if (x == 1 || x == n - 1) return true;
while (r--) {
x = (x * x) % n;
if (x == n - 1) return true;
}
return false;
}
bool Miller_Rabin(LL n) {
if (n == 1) return false;
for (int i = 0; i < len; i++)
if (n == base[i])
return true;
for (int i = 0; i < len; i++)
if (n % base[i] == 0)
return false;
LL m = n - 1, r = 0;
while (!(m & 1)) {
r++;
m >>= 1;
}
for (int i = 0; i < len; i++) {
if (!judge(base[i], n, m, r))
return false;
}
return true;
}