为什么要学习Miller-Rabin ?
之前一直认为素性测试可以使用费马小定理的逆命题,虽说会有一定的概率判错,多选几个就好了。我现在才知道存在一种Carmichael Number。
对于任意与n互质的数x, 都有 x n − 1 = 1 ( m o d n ) x^{n-1}=1 (mod\ n) xn−1=1(mod n),那么n称作Carmichael Number。
可以发现,无论我们选择多少个素数x,都无法排除Carmichael Number,Miller-Rabin应运而生。
流程前的说明
我们需要一些引理和规定。
- 若
p
p
p为素数,且
x
2
=
1
(
m
o
d
p
)
(
0
<
x
<
p
)
x^2=1(mod\ p)(0 < x < p)
x2=1(mod p)(0<x<p),则
x
=
1
x=1
x=1或
x
=
p
−
1
x=p-1
x=p−1。
证明如下:
∵ x 2 = 1 ( m o d p ) \because x^2 = 1 (mod\ p) ∵x2=1(mod p)
∴ x 2 − 1 = 0 ( m o d p ) \therefore x^2 - 1 = 0 (mod\ p) ∴x2−1=0(mod p)
∴ ( x + 1 ) ( x − 1 ) = 0 ( m o d p ) \therefore (x + 1) (x - 1) = 0 (mod\ p) ∴(x+1)(x−1)=0(mod p)
∴ p ∣ ( x + 1 ) ( x − 1 ) \therefore p | (x + 1)(x - 1) ∴p∣(x+1)(x−1)
∵ p i s a p r i m e \because p\ is\ a\ prime ∵p is a prime
∴ x = 1 或 x = p − 1 \therefore x = 1 或 x = p - 1 ∴x=1或x=p−1 - 所以上面这个定理的逆否命题就是:若 x ! = 1 x!=1 x!=1且 x ! = p − 1 x!=p-1 x!=p−1,则p不为素数或 x 2 ! = 1 ( m o d p ) ( 0 < x < p ) x^2!=1(modp)(0 < x < p) x2!=1(modp)(0<x<p)。换言之,若 x ! = 1 x!=1 x!=1且 x ! = p − 1 x!=p-1 x!=p−1且 x 2 = 1 ( m o d p ) ( 0 < x < p ) x^2=1(modp)(0 < x < p) x2=1(modp)(0<x<p),则 p p p一定不是质数,这一点在后面的代码里面有体现。
- 下文中, n n n都是需要判断的数。
- 下文的运算都是在 m o d n mod\ n mod n意义下进行的。
Miller-Rabin的流程
这里介绍我认为比较好懂的一种表述。
1:判断 n n n是否是 2 2 2的倍数。
如果 n n n是 2 2 2的倍数的话,有两种情况:
- n = 2。2是唯一的偶质数,后面没法判断。我们需要把它单独处理。
- n != 2。 它一定不是一个质数,我们就不用继续判断了。
2:把 n − 1 n-1 n−1分解成 2 k ∗ m 2^k * m 2k∗m的形式。
因为我们已经做了步骤1,所以 n n n一定是一个奇数。 n − 1 n-1 n−1就一定可以分解成 2 k ∗ m 2^k * m 2k∗m的形式。我们算出 k k k和 m m m。
3:随机选择一个正整数 a a a,计算出Miller-Rabin序列
我们构造这样一个序列:
m
2
1
∗
m
2
2
∗
m
⋯
⋯
2
k
∗
m
m\quad2^1*m\quad2^2*m\cdots\cdots\quad2^k*m
m21∗m22∗m⋯⋯2k∗m
构造这样一个序列有什么好处呢,我们发现:如果这个序列的每个数都是 a a a的次数的话,那么每一项可以由前一项平方得到。根据引理,我们可以通过判断 a 2 i ∗ m a^{2^i*m} a2i∗m与 1 1 1和 n − 1 n-1 n−1的关系来确定一个数不是质数。
4:判断 a 2 k ∗ m a^{2^k*m} a2k∗m与 1 1 1的关系
这里是根据费马小定理的逆命题,增大正确的机率。
5:重复步骤3、4,增大正确的机率。
正确性说明
可以证明单次Miller-Rabin的正确概率大于 3 4 \frac{3}{4} 43,我们重复若干次可以增大这个概率。
Miller-Rabin虽然有一定的概率出错,但在重复20次的情况下,实践证明1e7以内的质数不会判断出错。
复杂度说明
看具体实现,如果里面写了 O ( l o g n ) O(logn) O(logn)的大数乘法,复杂度就是 O ( l o g 2 n ) O(log^2n) O(log2n)的,否则是 O ( l o g n ) O(logn) O(logn)的。
typedef long long LL;
inline LL q_p(LL a, LL b, LL p) {
LL res = 1;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
inline LL q_c(LL a, LL b, LL p) {
return a * b - (LL)((LDB)a * b / p) * p;
}
inline int Miller_Rabin(LL n) {
if (n == 2) return 1;
if (n == 1 || !(n & 1)) return 0;
LL k = 0, m = n - 1;
while (!(m & 1)) {
k++;
m >>= 1;
}
for (int i = 1; i <= 20; ++i) {
LL a = rand() % (n - 1) + 1;
LL x = q_p(a, m, n), y;
for (int j = 1; j <= k; ++j) {
y = q_c(x, x, n);
if (x != 1 && x != n - 1 && y == 1) return 0;
x = y;
}
if (y != 1) return 0;
}
return 1;
}
后记
这是本人的第一篇blog, 由于本人水平有限,如有错漏之处请不吝指正。QQ:1902643000,欢迎一起讨论。
update
随机的整数a一定要在(0,n - 1)范围之内。但事实上,如果我们选择 2 , 3 , 7 , 61 , 24251 , 9875321 2,3,7,61,24251,9875321 2,3,7,61,24251,9875321这5个质数作为a的话,在 1 0 14 10^{14} 1014内不存在误判。