有时候我们想快速的知道一个数是不是素数,而这个数又特别的大导致 O( ) 的算法不能通过,这时候我们可以对其进行 Miller-Rabin 素数测试,可以大概率测出其是否为素数。
(1)费马小定理:当 为质数,有
,不过反过来不一定成立,也就是说,如果
,
互质,且
,不能推出
是质数,比如
数(这个就自行百度吧)
(2)二次探测:如果 是一个素数,
, 则方程
的解为
或
证明转载费马小定律&二次探测的证明
(1)对于偶数和 0,1,2 可以直接判断。
(2)设要测试的数为 ,我们取一个较小的质数
,设
,满足
(其中
是奇数)。
(3)我们先算出 ,然后不断地平方并且进行二次探测(进行
次)。
(4)最后我们根据费马小定律,如果最后 ,则说明
为合数。
(5)多次取不同的 进行
素数测试,这样可以使正确性更高
(1)我们可以多选择几个 ,如果全部通过,那么
大概率是质数。
(2) 素数测试中,“大概率”意味着概率非常大,基本上可以放心使用。
(3)当 取遍小等于 30 的所有素数时,可以证明
范围内的数不会出错。
(4)代码中我用的 类型,不过实际上
素数测试可以承受更大的范围。
(5)另外,如果是求一个
类型的平方,可能会爆掉,因此有时我们要用“快速积”,不能直接乘。
#include
#include
#include
using namespace std;
int prime[10]={2,3,5,7,11,13,17,19,23,29};
int Quick_Multiply(int a,int b,int c) //快速积(和快速幂差不多)
{
long long ans=0,res=a;
while(b)
{
if(b&1)
ans=(ans+res)%c;
res=(res+res)%c;
b>>=1;
}
return (int)ans;
}
int Quick_Power(int a,int b,int c) //快速幂,这里就不赘述了
{
int ans=1,res=a;
while(b)
{
if(b&1)
ans=Quick_Multiply(ans,res,c);
res=Quick_Multiply(res,res,c);
b>>=1;
}
return ans;
}
bool Miller_Rabin(int x) //判断素数
{
int i,j,k;
int s=0,t=x-1;
if(x==2) return true; //2是素数
if(x<2||!(x&1)) return false; //如果x是偶数或者是0,1,那它不是素数
while(!(t&1)) //将x分解成(2^s)*t的样子
{
s++;
t>>=1;
}
for(i=0;i<10&&prime[i]