1. 程式人生 > 其它 >「學習筆記」Miller Rabin 素數測試

「學習筆記」Miller Rabin 素數測試

$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;
}