Miller-Rabin素数测试
算法实现原理:若p为素数,a^(p-1)≡1(mod p) 费马小定理
正确性:一次为75%,第T次为1-1/(4^T).
流程:
1.输入待判定的数N
2.循环 T>=10遍
1*. RAND一个数A<N,A=rand()%(n-2)+2,把它扔到快速幂中计算a^(N-1)%N
2*. 若答案等于1,通过测试,再试几组数据;否则,失败,退出测试
流程中涉及快速幂取模和 大数相乘取模 ------> 速度慢,若两数相乘大于十八位,仿照快速幂取模。
(没有什么鬼二次探测定理,多算几次就好了)
hihocoder: #1287 : 数论一·Miller-Rabin质数测试
CODE:
#include<iostream> #include<cstdio> #include<cstring> #include<ctime> #include<cstdlib> #define ll long long #define count 10 ll jia(ll m,ll n,ll k){ ll ans=0; ll ret=m; while(n){ if(n&1) ans=(ans+ret)%k; ret=ret*2%k; n>>=1; } return ans; } //m*n%k ll exp(ll m,ll n,ll k){ ll ans=1; for(;n;n>>=1,m=jia(m,m,k)) if(n&1) ans=jia(ans,m,k); return ans; } //m^n%k bool miller(ll n){ if(n==2) return true; if(n==1) return false; for(int i=1;i<=count;i++){ ll a=rand()%(n-2)+2; if(exp(a,n-1,n)!=1) return false; } return true; } //a^(p-1)同余1(mod p)
int main(){ freopen("check.in","r",stdin); freopen("check.out","w",stdout); srand(time(NULL)); ll m,n; scanf("%lld",&m); for(int i=1;i<=m;i++){ scanf("%lld",&n); if(miller(n)) printf("Yes\n"); else printf("No\n"); } return 0; }
快速幂取模:
1 ll exp(ll m,ll n,ll k){ 2 ll ans=1; 3 for(;n;n>>=1,m=jia(m,m,k)) 4 if(n&1) 5 ans=jia(ans,m,k); 6 return ans; 7 } //m^n%k
大数相乘取模:
1 ll jia(ll m,ll n,ll k){ 2 ll ans=0; 3 ll ret=m; 4 while(n){ 5 if(n&1) ans=(ans+ret)%k; 6 ret=ret*2%k; 7 n>>=1; 8 } 9 return ans; 10 } //m*n%k