Miller-Rabin 素性测试算法
前提
Miller-Rabin 素性测试算法需要如下两个引理:
1. 费马小定理
设 是素数, 为整数,且 ,则
证明:
2. 二次探测定理
设 是一个素数,且 ,则方程 的解为 或 。
证明:
算法介绍
首先,费马小定理只是判定 为质数的必要条件。即费马小定理不成立, 一定是合数;费马小定理成立, 也有可能不是质数。
下面来看 Miller-Rabin 算法的分析过程:
假设 为素数且 ,则 为偶数。令 。
随机选取整数 。
由费马小定理可得 。
再由二次探测定理可得 或 。
若 成立,那么再由二次探测定理可得 或 ……
反复使用二次探测定理拆解,直到拆解到 或 。
总结一下: 或存在 使得 ,则称 通过 Miller 测试。
但是还存在一种伪素数,它们可以通过 Miller 测试但却不是素数。
但是经过证明 Miller-Rabin 算法的错误率小于等于 。若用不同的素数作为 测验 次,错误率可降低至 。
这里还有一个小技巧。如果被测数小于 4759123141 那么只需要测试 3 个底数 2,7,61即可。当然,你测试的越多,范围也就越大。如果你用前7个素数(2,3,5,7,11,13,17)测试,不超过 341550071728320 都是正确的。如果你选用2,3,7,61,24251作为底数,那么 内唯一的伪素数是 46856248255981,是 4840261 的倍数。对于 OIer 来说,已经非常够用了。
Code
当然,对于身为OIer的我们来说,代码肯定是最重要的。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Test[5] = {2,3,7,61,24251};
int tsped(int a,int b,int m){
int ans=0;
for(;b;b>>=1,(a<<=1)%=m)
if(b&1)(ans+=a)%=m;
return ans;
}
int qpow(int a,int b,int m){
int ans=1;
for(;b;b>>=1,a=tsped(a,a,m))
if(b&1)ans=tsped(ans,a,m);
return ans;
}
bool Miller_Rabin(int n){
if(n==2)return true;
if(n<2||!(n&1))return false;
if(!(n%4840261))return false;
int m=n-1,q=0;
while(!(m&1))q++,m>>=1;
for(int i=0;i<5;i++){
if(Test[i]==n)continue;
int a=qpow(Test[i],m,n),b;
for(int j=1;j<=q;j++){
b=tsped(a,a,n);
if(b==1&&a!=1&&a!=n-1)
return false;
a=b;
}
if(b!=1)return false;
}
return true;
}
signed main(){
int n;
cin>>n;
while(n--){
int a;
cin>>a;
cout<<Miller_Rabin(a)<<endl;
}
return 0;
}
本文作者:ASnown
本文链接:https://www.cnblogs.com/As-Snow/p/16938849.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步