準備知識:
梅森素數:它是發現已知最大素數的有效途徑。如果m是一個正整數,且是一個素數,則2^m-1必是素數。反之,如果m是一個正整數、素數,且2^m-1稱作第m個梅森數;如果p是一個素數,並且也是素數,那麼就稱爲梅森素數。而梅森數可能是素數,也可能是合數。
(由於很多word公式無法導入,只能以截圖方式展現。)
Lucas-Lehmer判定法
#include <iostream>
using namespace std;
#define ll long long
ll multi(ll a,ll b,ll mod)
{
ll ans=0;
while(b>0)
{
if(b&1)
{
ans=(ans+a)%mod;
}
b>>=1;
a=(a<<1)%mod;
}
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int p;
ll r1 = 4,r2=0,mp=1;
cin>>p;
mp = (mp<<p) -1;
int i;
for(i=0;i<p-2;i++)
{
r2 = multi(r1,r1,mp);
r2 = (r2 - 2)%mp;
r1 = r2;
}
if(r2==0||p==2)
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
}
return 0;
}
Miller測試法
這裏用快速冪時,我們需要注意的是,如果直接a*a%n是有可能有溢出風險的,因爲都是long long 類型的。所以這裏還需要加入一個基於加法的快速乘法取模法,來求a*a%n。
#include <iostream>
#include <time.h>
#include <cstdio>
#include <cstdlib>
#define ll long long
#define Times 12
using namespace std;
ll random(ll n)
{
return (ll)((double)rand()/RAND_MAX*n+0.5);
}
ll multi(ll a,ll b,ll m)
{
ll ans = 0;
while(b>0)
{
if(b&1)
{
ans=(ans+a)%m;
}
b>>=1;
a=(a<<1)%m;
}
return ans;
}
ll quick_mod(ll a,ll b,ll m)
{
ll ans = 1;
while(b)
{
if(b&1)
{
ans = multi(ans,a,m);
//ans=ans*a%m;
}
b>>=1;
a = multi(a,a,m);
//a=a*a%m;
}
return ans;
}
bool Witness(ll a,ll n)
{
ll m = n-1;
int j=0;
while(!(m&1))
{
j++;
m>>=1;
}
ll x = quick_mod(a,m,n); //a^(n-1)%n
if(x==1 || x==n-1)
return false;
while(j--)
{
x = x*x%n;
if(x == n-1)
return false;
}
return true;
}
bool miller_rabin(ll n)
{
if(n<2) return false;
if(n==2) return true;
if( !(n&1) ) return false;
for(int i=1;i<=Times;i++)
{
ll a = random(n-2)+1;
if(Witness(a,n)) return false;
}
return true;
}
int main()
{
int p,T;
cin>>T;
while(T--)
{
cin>>p;
ll n;
n=(ll)1<<p;
n=n-1;
if(miller_rabin(n))
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
}
return 0;
}