MillerRabin素性判定
随机的素性判定算法,但判定次数更多正确率越大。
1.前置知识:
-
费马小定理
\(a^{p-1}\equiv 1 \mod p\),p为任意质数,a为任意整数
并且逆否命题成立,即:对于任意整数\(a<pa<p\),不满足\(a^{p−1}\equiv 1 \mod p\),则\(p\)为合数。
-
二次探测定理
如果有\(0< x < p\)并且\(p\)为素数,并且有方程\(x^2\equiv 1 \mod p\),则方程有两解\(x_1=1,x_2=p-1\)
在\([2,p-1]\)中随机取\(a\),在\(s\)次探测以后判为不是合数后则为质数。
2.判定办法:
有\(p-1=2^{t}u\),取\(x[0]=a^u \mod p\),\(x[0]\)平方了\(t\)次以后则为\((a^u)^{2^t} \mod p\),即\(a^{2^tu} \mod p\)
如果不为\(1\),那么该数不是质数;如果为\(1\)但解不是\(1\)或\(p-1\)则该数不是质数。
判定\(s\)次即可,\(s\)通常取\(20\)等。
复杂度为\(O(slog_3n)\)。
值得注意的是数字较大的时候要使用慢速乘。
ll range(int l,int r) {
return abs(rand())%(r-l+1)+l;
}
// 当x很大时 long long会乘爆,需要使用慢速乘
ll SlowMul(ll a,ll b,ll mo) {
ll ret=0;
while(b) {
if(b&1) ret=(ret+a)%mo;
a=(a+a)%mo;
b>>=1;
}
return ret;
}
ll QuickPow(ll x,ll k,ll mo) {
ll ret=1ll;
while(k) {
if(k&1) ret=ret*x%mo;
x=x*x%mo;
k>>=1;
}
return ret;
}
bool MillerRabin(ll x) {
if(x==2) return true;
int t=0;
ll u=x-1;
while(!(u&1)) {
t++;
u>>=1;
}
int s=20;
ll now,pre;
while(s--) {
ll a=range(1,x-1);
now=QuickPow(a,u,x);
for(int z=0;z<t;z++) {
pre=now;
now=now*now%x;
if(now==1 && pre!=1 && pre!=x-1) return false;
}
if(now!=1) return false;
}
return true;
}