mr演算法全稱是miller-rabin測試,是乙個非確定的演算法,用於判斷乙個數是否是質數.雖然是乙個非確定的演算法,但是只要巧妙地選取引數,在一定範圍內就是乙個確定性的演算法.
前置條件:費馬小定理1 ≡ a^(p-1) (mod p)
miller和rabin兩個人的工作讓fermat素性測試邁出了革命性的一步,建立了傳說中的miller-rabin素性測試演算法。 新的測試基於下面的定理(二次探測定理
):如果p是素數,x是小於p的正整數,且x^2 mod p = 1
,那麼要麼x=1,要麼x=p-1。這是顯然的,因為x^2 mod p = 1相當於p能整除x^2-1,也即p能整除(x+1)(x-1)
。由於p是素數,那麼只可能是x-1
能被p整除(此時x=1)或x+1
能被p整除(此時 x=p-1)。
這就 是miller-rabin素性測試的方法。不斷地提取指數n-1中的因子2,把n-1表示成注意是當取模為1時才能繼續降冪取模,取模為n-1時演算法終止(但是之後的演算法實際上不是這麼死板地實現的).d*2^r(其中d是乙個奇數)
。那麼我們需要計算的東西就 變成了a的d*2^r次方除以n的餘數
。於是,a^(d * 2^(r-1))
要麼等於1,要麼等於n-1。如果a^(d * 2^(r-1))
等於1,定理繼續適用於a^(d * 2^(r-2))
,這樣不斷開方開下去,直到對於某個i滿足a^(d * 2^i) mod n = n-1或者最後指數中的2用完了得到的a^d mod n=1或n-1。這樣,fermat小定理加強為如下形式:
盡可能提取因子2, 把n-1表示成d*2^r,如果n是乙個素數,那麼或者a^d mod n=1,或者存在某個i使得a^(d*2^i) mod n=n-1 ( 0<=i如果你每次都用前7個素數(2, 3, 5, 7, 11, 13和17
)進行測試,所有不超過341 550 071 728 320
(即3.4e14)的數都是正確的。如果選用2, 3, 7, 61和24251
作為底數,那麼10^16內唯一的強偽素數為46 856 248 255 981
(即4.6e13)。
ll quick_multiply
(ll a, ll b, ll c)
//快速積(和快速冪差不多)
return ans;
}ll quick_power
(ll a, ll b, ll c)
//快速冪,這裡就不贅述了
return ans;
}bool miller_rabin
(ll n,
int a, ll d)
//判斷素數
ll t =
quick_power
(a, d, n)
;while
((d != n -1)
&&(t !=1)
&&(t != n -1)
)return
(t == n -1||
(d &1)
==1);
}bool isprime
(ll n)
;for
(int i =
0; i <10;
++i)
}return true;
}
給你乙個p,乙個a,問p是不是基於a的偽素數.
偽素數是指根據費馬小定理判斷是素數的,實際上卻不是素數的數.
這題的解法很顯然,就是先用費馬小定理判斷一下是不是,再真正地判斷一下是不是.而真正的判斷的話,很多題解上給出的是暴力判斷,我們就以此當做mr素性測試的模板題吧.
費馬小定理前文提到了,但是在實際過程中發現了一點問題:
如果根據1 ≡ a^(p-1) (mod p)
,居然會wa,但是如果根據p ≡ a^(p) (mod p)
,就能過.這實在是匪夷所思,之後再深入**.
#include
using namespace std;
#define rd(x) (rand()%(x))
typedef
long
long ll;
int prime=
;ll quick_multiply
(ll a, ll b, ll c)
//快速積(和快速冪差不多)
return ans;
}ll quick_power
(ll a, ll b, ll c)
//快速冪,這裡就不贅述了
return ans;
}bool miller_rabin
(ll n,
int a, ll d)
//判斷素數
ll t =
quick_power
(a, d, n)
;// 這個迴圈運用了一些技巧,
// 盡可能提取因子2, 把n-1表示成d*2^r
// 如果n是乙個素數,
// 那麼或者a^d mod n=1,
// 或者存在某個i使得a^(d*2^i) mod n=n-1 ( 0<=i// 迴圈的次數應該是r,也就是初始的時候d移除後面連續的所有0,最後再迴圈裡一次一次挪回來
// 如果d又重新變成了n-1,那麼說明迴圈終止
// 此處的t就是a^(d*2^i) mod n ( 0<=i// 還有一種可能是a^d mod n == 1
// 這種情況只會發生在第一次迴圈中,所以如果是因為t==1而跳出迴圈,則需要判斷d是否是奇數
// 因為只有在迴圈的第一輪(d為奇數),t==1才能認為是n是質數的證據
while
((d != n -1)
&&(t !=1)
&&(t != n -1)
)return
(t == n -1||
(d &1)
==1);
}bool isprime
(ll n)
;for
(int i =
0; i <10;
++i)
}return true;
}int
main()
bool f1 =
isprime
(p);
bool f2 =
quick_power
(n, p, p)
== n;
// 此處實在是匪夷所思 寫成 n^(p-1) == 1 (mod p) 就會wa,但是這樣寫就沒問題
if(f1)
else
if(f2)
else
}return0;
}
Miller Rabin素性測試與二次探測
首先是一些概念 利用二次探測定理,只需要探測s次就可以將錯誤率降到2 s 好像是這樣吧。反正很低就對了 因此也不會多花多少時間。記得判素時的細節處理以及快速冪取模。應該是最簡潔的模板了。include using namespace std typedef long long ll ll prime...
費馬小定理(MR素數探測法) v2 0
include include include include using namespace std typedef long long ll ll powermod ll a,ll b,ll n bool witness ll a,ll n ll x powermod a,m,n if x 1 ...
Miller Rabin素性測試
博主鏈結 隨機素數測試 偽素數原理 call bool res miller n 快速測試n是否滿 足素數的 必要 條件,出錯概率極低 對於任意奇數n 2和正整數s,演算法出錯概率 2 s include include define ll long long int define met a me...