费马小定理
p
p
p 为质数,
a
a
a 为任意自然数, 则
a
p
≡
a
(
m
o
d
p
)
⟺
a
p
−
1
≡
1
(
m
o
d
p
)
a^{p} \equiv a\pmod p \iff a^{p-1} \equiv 1 \pmod p
a p ≡ a ( m o d p ) ⟺ a p − 1 ≡ 1 ( m o d p )
证明略。
二次探测定理
p
p
p 为质数,则
x
2
≡
1
(
m
o
d
p
)
x^2 \equiv 1 \pmod p
x 2 ≡ 1 ( m o d p ) 的解为
x
1
=
1
,
x
2
=
p
−
1
x_1 = 1, x_2 = p-1
x 1 = 1 , x 2 = p − 1 。
略证:
x
2
≡
1
(
m
o
d
p
)
x
2
−
1
≡
0
(
m
o
d
p
)
(
x
+
1
)
(
x
−
1
)
≡
0
(
m
o
d
p
)
p
∣
(
x
−
1
)
×
(
x
+
1
)
x^2 \equiv 1 \pmod p \\ x^2 - 1 \equiv 0 \pmod p \\ (x +1)(x-1) \equiv 0 \pmod p \\ p | (x - 1)\times (x+1)
x 2 ≡ 1 ( m o d p ) x 2 − 1 ≡ 0 ( m o d p ) ( x + 1 ) ( x − 1 ) ≡ 0 ( m o d p ) p ∣ ( x − 1 ) × ( x + 1 )
Miller-Rabin
我们都知道,如果
p
p
p 为质数那么有
a
p
−
1
≡
1
(
m
o
d
p
)
a^{p-1} \equiv 1 \pmod p
a p − 1 ≡ 1 ( m o d p ) 。但反命题不一定成立,比如令
a
=
2
a=2
a = 2 ,那么有
2
340
m
o
d
341
=
1
2^{340} \bmod 341 = 1
2 3 4 0 m o d 3 4 1 = 1 ,但是
341
=
11
×
31
341 = 11 \times 31
3 4 1 = 1 1 × 3 1 。那么再试一下
a
=
3
a=3
a = 3 ,发现
3
340
m
o
d
341
=
56
3^{340} \bmod 341 = 56
3 3 4 0 m o d 3 4 1 = 5 6 ,所以
341
341
3 4 1 不是质数。
那么能不能多选几个质数去做检测呢?但是有一些合数,叫做 Carmichael 数,比如
561
=
3
×
11
×
17
561 = 3\times11 \times17
5 6 1 = 3 × 1 1 × 1 7 ,所有合法的底数都无法将它检测出来。
那么接下来就是正题了——Miller-Rabin 素性测试算法。先拿
341
341
3 4 1 举个栗子,看看这个算法在干什么。
先说明一个显而易见的命题,对于任意质数
p
p
p 有
2
∣
p
−
1
2| p -1
2 ∣ p − 1 。那么看看 Miller-Rabin 干了什么。
因为
2
340
≡
1
(
m
o
d
341
)
2^{340} \equiv 1 \pmod {341}
2 3 4 0 ≡ 1 ( m o d 3 4 1 ) ,那么有
2
170
2
≡
1
(
m
o
d
341
)
2^{{170}^2} \equiv 1 \pmod {341}
2 1 7 0 2 ≡ 1 ( m o d 3 4 1 ) ,若将
2
170
2^{170}
2 1 7 0 看作一个整体,根据二次探测定理,如果
341
341
3 4 1 是一个质数,那么
2
170
m
o
d
341
=
1
/
340
2^{170} \bmod 341 = 1 / 340
2 1 7 0 m o d 3 4 1 = 1 / 3 4 0 。可以发现
2
170
m
o
d
341
2^{170} \bmod 341
2 1 7 0 m o d 3 4 1 为
1
1
1 。那么还适用二次探测定理,再看看
2
85
m
o
d
341
2^{85} \bmod 341
2 8 5 m o d 3 4 1 ,发现它为
32
32
3 2 ,所以
341
341
3 4 1 不是质数。
int ksm ( int a, int k, int p) {
int res = 1 ;
while ( k) {
if ( k & 1 ) res = res * a % p;
a = a * a % p;
k >>= 1 ;
}
return res % p;
}
int MR ( int x, int p) {
if ( ksm ( x, p- 1 , p) != 1 ) return 0 ;
int k = p - 1 ;
while ( ! k & 1 ) {
k >>= 1 ;
int t = ksm ( x, k, p) ;
if ( t == p - 1 ) return 1 ;
if ( t != 1 ) return 0 ;
}
return 1 ;
}
int RP ( int p) {
if ( p == 2 || p == 3 || p == 5 || p == 7 || p == 11 ) return 1 ;
if ( p == 0 ) return 0 ;
return MR ( 2 , p) && MR ( 3 , p) && MR ( 5 , p) && MR ( 7 , p) && MR ( 11 , p) ;
}
int main ( ) {
while ( 1 ) {
int x = read ( ) ;
printf ( "%d\n" , RP ( x) ) ;
}
return 0 ;
}
可以发现 Miller-Rabin 的时间按复杂度为
O
(
k
log
2
n
)
O(k \log^2 n)
O ( k log 2 n ) ,其中
k
k
k 为测试次数,通常五次就够了。