普通代码:
bool prime(int n)
{
if(n==2) return true;
if(n<2||n%2==0) return false;
int j=3;
while(j<=(int)sqrt(n))
{
if(n%j==0) return false;
j=j+2;
}
return true;
}
利用费马小定理,对于给定的整数n,取一个正整数 a (1 < a < n ), 通过计算
d
≡
a
n
−
1
(
m
o
d
n
)
d \equiv a^{n-1}(mod \ n)
d≡an−1(mod n)来判定整数n的素性。
素数测试: 设a , n 为正整数
(1)若
a
n
−
1
a^{n-1}
an−1 ≠ 1
(
m
o
d
n
)
(mod \ n)
(mod n),则n一定为合数。
(2)若
a
n
−
1
≡
1
(
m
o
d
n
)
a^{n-1}\equiv 1 (mod \ n)
an−1≡1(mod n),则几乎可以肯定地确认n为素数,因为出错率很小。
注意:如n=1是上面就不成立,
2
34
m
o
d
(
341
)
=
1
2^{34}mod(\ 341)=1
234mod( 341)=1,但341是合数。为了提高测试的准确性,可以随机地选取整数1 < a < n - 1。 费马小定理毕竟只是素数判定的一个必要条件
欧拉定理 :
设a和m是整数(m>0)。记
φ
(
m
)
\varphi (m)
φ(m)是1到m的整数中与m互素的整数的个数,则
a
φ
(
m
)
≡
1
(
m
o
d
m
)
a^{\varphi(m)}\equiv 1 (mod \ m)
aφ(m)≡1(mod m).
证明:略。
为增加测试效率,可利用二次探测定理:如果p是一个素数,0<x<p,则方程
x
2
x^{2}
x2≡1(mod p)的解为x=1或x=p-1。
一旦发现违背二次探测条件,即可得出n不是素数的结论。
Miller-Rabin 素数测试算法如下:
输入: n与a(a在2,···,n-1这些数中随机取值)
输出: true 或 false
关于讲解Miller-Rabin的博文,讲得比较有条理
对应的模板题 hdu 2138
上面那篇博客里的主要代码:
bool Miller_Rabin(int n)//利用Miller_Rabin判断n是否为素数
{
if(n==2) return true;
if(n<2||(n&1)==0) return false;
ll t,a;
ll y;
ll x;
ll u=Mod_t(n-1,t);//求出n-1=u * 2^t 中的u,与t的值
for(int i=0;i<10;i++) //这里表示用几次a的值,次数越多准确度越高,一般2次正确率就有点高了,一次的话题目数据比较水,还是可以过的
{
a=rand()%(n-1) + 1;
x=Mod_u(a, u, n);//求出a^u mod n的值
for(int j=0;j<t;j++)
{
y=(x*x)%n;
if(y==1&& x!=1 && x!=n-1)
return false;
x=y;
}
if(x!= 1 ) return false ; //经过t次后x=a^(n-1) mod n, (费马小定理)若x不为1,说明n一定不为素数
}
return true;
}
另一种表示
a
n
−
1
a^{n-1}
an−1形式,用二进制表示;
举例:
a
11
=
a
1011
(
幂
用
二
进
制
表
示
)
=
a
{
[
(
0
+
1
)
∗
2
+
0
]
∗
2
+
1
}
∗
2
+
1
=
[
(
1
∗
a
)
2
∗
1
]
2
∗
a
2
∗
a
a^{11}=a^{1011}(幂用二进制表示)= a^{\{\ [\ (0+1)*2+0\ ]*2+1 \ \}*2+1} \\ ={[(1*a)^2*1] ^2*a}^2*a
a11=a1011(幂用二进制表示)=a{ [ (0+1)∗2+0 ]∗2+1 }∗2+1=[(1∗a)2∗1]2∗a2∗a
下面的代码与上面不同的就是模拟这个运算过程
int B[1000];
ll get_B(int x)
{
int cnt=0;
while(x)
{
if(x&1)
B[cnt++]=1;
else
B[cnt++]=0;
x>>=1;
}
return cnt;
}
bool Rb(int n)
{
if(n==2) return true;
if(n<2||(n&1)==0) return false;
ll a=2;//这里a值取2
ll x=1;
ll y;
ll len=get_B(n-1);
for(int i=0;i<10;i++)
{
a=rand()%(n-1)+1;
x=1;
for(int i=len-1;i>=0;i--)
{
y=x*x%n;
if(y==1&& x!=1&&x!=n-1)
return false;
if(B[i]==1)
y=y*a%n;
// cout<<B[i]<<" "<<"y , x ="<<y<<";"<<x<<endl;
// else
// y=y*1%n;
x=y;
}
if(x!=1)
return false;
}
return true;
}