如同标题所述,Miller_Rabin 是用来测试一个数是否为素数的算法。然而,Miller_Rabin是有缺陷的,这就是它单次执行所得的结果并不完全正确,不过我们可以将这个算法多执行几次来让它的正确率趋近于 。
小定理:若 为素数, 为正整数,且 ,则 .
小定理的逆命题不是真命题,但是满足两个条件的 有很大概率是素数,所以多测试几次可以提高判断准确程度。
二次探测定理:如果 是一个素数, , 则方程 的解为 或 .
同样也是逆用这个定理,若 且 , ,则 一定不是质数,与 小定理结合提高准确度。
快速幂。
- 给定一个整数 ,即要求判断的数.
- 计算奇数 使得 .
- 选择随机数 (也可以是自己指定)
- 对于 , 若 ,则 通过测试。
- 或者,若 ,则 通过测试。
- 多次选取 ,若 全部通过,则判定 是素数。
由于Miller_Rabin是概率算法,所以要多次选取素数保证正确程度, 范围内 使用 这三个数即可。实在担心的话取 ,准确性就相当高了。
\\随机
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;
}