「學習筆記」Miller Rabin 素數測試
一.素數的定義
素數又稱素數。一個大於 \(1\) 的自然數,如果除了 \(1\) 或者它本身之外,沒有數字能被它整除,那麼這個數就叫做素數。
二.素數的基礎判斷
大家都知道,對於素數判斷,我們有一個時間複雜度為 \(O(\sqrt{(n)})\) 的演算法。
bool isprime (int n) {
for (int i = 2; i <= sqrt (n); i ++) {
if (n % i == 0) {
return false;
}
}
return true;
}
但是這個時間複雜度對於某些較大的數字無法通過。
這樣,就誕生了一個更高效的素數判斷方法:Miller Rabin
三.費馬小定理
若 \(p\) 為素數,整數 \(a\) 與 \(p\) 互素,則 \(a^{p-1} \equiv 1\pmod p\)。
我們設\(d×2^{r}=p-1\),那麼式子就轉化為 \(a^{d · 2^r} \equiv 1\pmod p\)。
四.二次探測定理
若 \(p\) 為素數,整數 \(x<p\) ,那麼對於 \(x^2 \equiv 1 \pmod p\) 的解 \(x\) 為 \(1\) 或 \(p - 1\)。
證明:
上述式子可以化為 \(x^2-1^2 \equiv 0 \pmod p\)。
根據平方差公式:\(a^2-b^2=(a+b)(a-b)\)
可以將上述式子化為: \((x+1)(x-1) \equiv 0 \pmod p\)。
因為 \(p\) 為素數,那麼 \((x+1)(x-1) = 0\) 或 \((x+1)(x-1)\) 為 \(p\) 的倍數。
那麼,當 \((x+1)(x-1) = 0\) 時,顯然 \(x=1\)。
當 \(p∣(x+1)(x-1)\) 時,\(x=p + 1\) 或 \(x=p-1\)。
由於 \(x<p\),所以 \(x=p + 1\) 不成立。
所以 \(x=1\) 或 \(x=p-1\)。
兩個定理結合起來,對於以下兩個式子,最少有一個式子被滿足:
-
\(a^d \equiv 1 \pmod p\)
-
對於 \(0 \le i < r\), \(a^{d · 2^i} \equiv -1\pmod p\)。
五.\(Miller Rabin\) 素數判斷
\(Miller Rabin\) 素數判斷的過程如下:
將 \(p-1\) 中的因子 \(2\) 個數提取出來,先設 \(d=p-1\),取
\(k\) 個數 \(1<a_1,a_2,a_3......a_k<p\) 帶入上述公式判斷是否構成條件。
對於 \(a\) 的個數,設一個適合的數字即可,在 \(7-15\) 之間都可以,經過測試,取前 \(k\) 個素數即可。
而這個演算法對於 \(long\) \(long\) 範圍之間的數的誤差率幾乎為 \(0\)。
時間複雜度為 \(O(k \log p)\)。
核心程式碼如下:
inline bool Miller_Rabin (ll n, ll a) {
ll d = n - 1, r = 0;
while (!(d & 1)) {//分解出所有的因子2。
r ++;
d >>= 1;
}
ll adn = ksm (a, d, n);
if (adn == 1) {//滿足公式1。
return true;
}
for (int i = 0; i < r; i ++) {
if (adn == n - 1) {//滿足公式2。
return true;
}
adn = mul (adn, adn, n); /不斷乘2的i次冪。
}
return false;
}