写在前面的话: 我已经无数次用过这个函数了,但是每一次都不是很理解,总是忘了里面的原理,还是写下来记录一下吧.
算法过程描述:
取
4
4
4个质数
t
e
s
t
test
test:
{
2
,
3
,
5
,
7
}
\left \{ 2,3,5,7 \right \}
{2,3,5,7},设检测的数为
p
p
p,并且设
x
x
x为
p
−
1
p-1
p−1。先将
x
x
x表示成
q
∗
2
k
q*2^{k}
q∗2k(其中
k
k
k为非负整数,
q
q
q为奇数),然后
∀
i
\forall i
∀i,设定初始值
a
a
a为
(
t
e
s
t
[
i
]
)
q
(test[i])^{q}
(test[i])q。每次计算
a
a
a的平方(在模
p
p
p运算下)
t
m
p
tmp
tmp,如果
t
m
p
tmp
tmp是
1
1
1,那么
a
a
a应该为
1
1
1或者
p
−
1
p-1
p−1,否则
x
x
x为合数。将
t
m
p
tmp
tmp赋值给
a
a
a。
∀
i
\forall i
∀i,上述过程重复
k
k
k次,最后
a
a
a如果不是
1
1
1,
x
x
x为合数。
涉及定理:
-
二次探测定理
对上述过程的疑问1:
\space\space\space\space 引自过程描述: 如果 t m p tmp tmp是 1 1 1,那么 a a a应该为 1 1 1或者 p − 1 p-1 p−1,否则 x x x为合数。
\space\space\space\space 证明: 由上述过程容易得: a 2 ≡ 1 m o d p a^2\equiv 1 \space mod\space p a2≡1 mod p,则应该有 ( a 2 − 1 ) ≡ 0 m o d p (a^{2}-1)\equiv 0 \space mod\space p (a2−1)≡0 mod p。所以容易得到: p ∣ ( a − 1 ) ( a + 1 ) p|(a-1)(a+1) p∣(a−1)(a+1)。.进一步来看, a − 1 a-1 a−1或 a + 1 a+1 a+1应该为 p p p的倍数(在模 p p p条件下, a a a为 1 1 1或者 p − 1 p-1 p−1),否则的话,( a − 1 a-1 a−1)和( a + 1 a+1 a+1)一定有两个因子或更多满足 b 1 ∗ b 2 ∗ b 3 ∗ . . . . = p b_{1}*b_{2}*b{3}*....=p b1∗b2∗b3∗....=p,则此时 p p p不是素数。 -
生成元定理
对上述过程的疑问2:
\space\space\space\space 引自过程描述: 最后 a a a如果不是 1 1 1, x x x为合数。
\space\space\space\space 证明:由过程描述容易看出 t e s t [ i ] test[i] test[i]为素数,所以在 m o d p mod\space p mod p的域中, t e s t [ i ] test[i] test[i]为生成元,所以经过 p − 1 p-1 p−1次转动之后即 ( t e s t [ i ] ) p − 1 (test[i])^{p-1} (test[i])p−1一定能转回到 1 1 1.如果没转回来,说明 m o d p mod\space p mod p不是域,也即 p p p不是素数。这里扩展一下,在 m o d p mod\space p mod p中, x x x的逆元为 x p − 2 x^{p-2} xp−2,如果 p p p较大,可以采用快速幂。
嗯,感觉现在懂了一点,放个代码吧,若您对我的描述有任何问题欢迎指出!
#include<bits/stdc++.h>
typedef long long ll;
int pow(int a, int b, int p)
{
int tmp = b;
int k = 0;
int sum = 1;
while (b)
{
if (b % 2 == 1)
{
sum = ((ll)sum*a) % p;
}
a = ((ll)a*a) % p;
b = b >> 1;
}
return sum;
}
int test[4] = { 2,3,5,7 };//这个test[i]做的是a,然后指数上是t
int rho(int x)
{
int p = x;
int k = 0;
//for (int i = 0; i < 4; i++)
//if (x == test[i])return 1;
x--;
while (!(x & 1))
{
x = x >> 1; k++;
}
for (int i = 0; i < 4; i++)
{
//if (test[i] == p)return 1;
if (test[i] == p)return 1;
int a = pow(test[i], x, p);//这步很关键,做平方的时候是a的t次幂,不是a
//同时有p=a^(t*2^k),这里,x=t,x已经被÷2处理过了
int nxt=a;
for (int j = 0; j < k; j++)
{
nxt = ((ll)a*a) % p;
if (nxt == 1 && a != 1 && a != p-1)
return 0;
a = nxt;
}
if (nxt != 1)
return 0;
}
return 1;
}
int main(void)
{
int n;
scanf_s("%d", &n);
int count = 0;
for (int i = 2; i <= n; i++)
{
//for(int j=0;j<test[i])
if (rho(i))count++;
}
printf("%d", count);
}