【数论】Miller_Rabin 素性测试
_GeorgeAAAADHD_ · · 个人记录
本篇博客将对素性测试的方法进行讲解。
Part 1. 小素数判定
没什么好说的,根号复杂度筛质因子,可以跑单个
代码:
bool isprime(int x){
if(x<2)return 0;
for(int i=2;i*i<=x;i++)if(x%i==0)return 0;
return 1;
}
Part 2. 大素数素性测试
素性测试是指在不对给定数进行质因子分解的情况下判断这个数是否为素数,通常包括确定性测试和概率性测试。
因为确定性测试十分复杂且比概率性测试慢很多,这里只讲解概率性测试。
Part 3. Fermat 素性测试
这种测试是使用费马小定理进行素数判定的方法。
设当前测试的数为
证明显然,单次测试复杂度为
然而这种方式会有较大的错误率,有一些合数对于一些基
Part 4. Miller_Rabin 素性测试
这种测试是基于 Fermat 素性测试上优化后的素性测试。
先来证明一个定理:
- 二次探测定理:如果
p 是奇素数,则x^2 \equiv 1 \pmod p 的解为x \equiv 1 \pmod p 或者x \equiv p - 1 \pmod p 。
证明:移项得
因为
解得
得证。
具体步骤如下:
-
选取一个素数
p ,判断n 是否等于p 或者为p 的倍数并做出判断。 -
用费马小定理判断其是否极有可能是一个素数。
-
利用二次探测定理判断其是否是一个素数。具体做法如下:
将
然后每次将左侧开方,第
一个小细节:
如果在某个时刻
注意:二次探测定理只能判奇素数,因此测试前就要特判素数
核心代码如下:
int pp[20]={2,3,5,7,11,13,17,19,131,1145141};
int y=5;
ll qpow(ll a,ll b,ll md){
a%=md;
ll ans=1;
while(b){
if(b&1)ans=ans*a%md;
a=a*a%md;
b>>=1;
}
return ans;
}
struct Miller_Rabin{
inline bool check(ll x,ll p){
if(x%p==0||qpow(p,x-1,x)!=1)return 0;
ll k=x-1;
while(k%2==0){
ll t=qpow(p,k>>=1,x);
if(t!=1&&t!=x-1)return 0;
if(t==x-1)return 1;
}
return 1;
}
inline bool isprime(ll x,ll y){
if(x<2)return 0;
if(x==2)return 1;
for(ll i=0;i<y;i++){
if(x==pp[i])return 1;
if(check(x,pp[i])==0)return 0;
}
return 1;
}
}mr;
模版题:P5285 2p部分。