1. 程式人生 > 其它 >米勒羅賓素性測試

米勒羅賓素性測試

篩選法的效率很高,但是遇到大素數就無能為力了。

米勒羅賓素性測試是一個相當著名的判斷是否是素數的演算法

核心為費馬小定理:

假如 \(a\) 是整數,\(p\) 是質數,且 \(a,p\) 互質,那麼 \(a\)\((p-1)\) 次方除以 \(p\)
的餘數恆等於1。

逆推一下即 \(p\)\(a^{p-1}%p!=1(0<a<p)\) ,它一定是合數。

如果 \(a^{p-1}%p=1(0<a<p)\) 則它可能是合數可能是素數。概率演算法的概率就在這個 a上體現。

具體過程:

1 隨機取一個 \(a\)

2 如果 它不滿足 \(a^{n-1}%n=1\)

3 則它一定是合數

4 退出

5 如果它滿足 \(a^(n-1)%n=1\)

6 則它可能是一個素數

7 回到1

米勒素數測試的合數為偽素數與Carmichael(強偽素數)

Carmichael數是非常少的,在 \(1~100000000\) 範圍內的整數中,只有 \(255\) 個Carmichael數。

為此有二次探測定理以確保該數為素數:

如果p是一個素數,\(0<x<p\) ,則方程 \(x^2≡1(mod p)\) 的解為 \(x=1,p-1\)

程式碼實現

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll q_mul(ll a,ll b,ll p)
{
	ll ans=0;
	while(b)
	{
		if(b&1)
			ans=(ans+a)%p;
		a=(a<<1)%p;
		b>>=1; 
	}
	return ans;
}
ll q_pow(ll a,ll b,ll p)
{
	ll ans=1;
	while(b)
	{
		if(b&1)
			ans=q_mul(ans,a,p);
		a=q_mul(a,a,p);
		b>>=1;
	}
	return ans;
}
bool Miller_Rabin(ll n){
    if(n==2)return true;
    if(n<2||!(n&1))return false;
    int t=2,r=0;
    ll m=n-1;
    while(m%2==0){
        r++;
        m>>=1;
    }
    srand(100);
    while(t--)
	{
        ll a=rand()%(n-1)+1;
        ll x=q_pow(a,m,n),tmp=0;
        for(int i=0;i<r;i++){
            tmp=q_mul(x,x,n);
            if(tmp==1&&x!=1&&x!=n-1)return false;
            x=tmp;
        }
        if(tmp!=1)return false;
    }
    return true;
}

說明:

Miller-Rabin是隨機演算法

如果對這個過程重複100次,每次都沒說它是合數,那這個數是素數的概率只有(1/2)^5100