nefu120-梅森素數(Lucas-Lehmer判定法和Miller測試法)


準備知識:

梅森素數:它是發現已知最大素數的有效途徑。如果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;


}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章