1. 程式人生 > 實用技巧 >二、Lambda表示式

二、Lambda表示式

Miller-Rabin質數測試

資料源:

Miller-Rabin素數測試演算法——forever_dreams
hihoCoder #1287

正文:

非精確演算法警告

作用

當我們需要判斷素數時,如果樸素\(O(\sqrt{n})\)演算法不能通過,那麼可以通過Miller-Rabin素數測試,來大概率地判斷其是否為素數。

兩個基礎理論

(1)費馬小定理:當 p 為質數,有 \(a^{p-1}\equiv 1(mod\ p)\) ,不過反過來不一定成立,也就是說,如果 a , p 互質,且 \(a^{p-1}\equiv 1(mod\ p)\) ,不能推出 p 是質數,比如\(Carmichael\)

數(這個就自行百度吧)

(2)二次探測:如果 p 是一個素數,0 < x < p, 則方程 \(x^{2}\equiv 1(mod\ p)\) 的解為 x = 1 或 x = p - 1

兩個基本理論的證明

費馬小定律&二次探測的證明

小Hi:這種質數演算法是基於費馬小定理的一個擴充套件,首先我們要知道什麼是費馬小定理:

費馬小定理:對於質數p和任意整數a,有a^p ≡ a(mod p)(同餘)。反之,若滿足a^p ≡ a(mod p),p也有很大概率為質數。
將兩邊同時約去一個a,則有a^(p-1) ≡ 1(mod p)

也即是說:假設我們要測試n是否為質數。我們可以隨機選取一個數a,然後計算a^(n-1) mod n,如果結果不為1,我們可以100%斷定n不是質數。

否則我們再隨機選取一個新的數a進行測試。如此反覆多次,如果每次結果都是1,我們就假定n是質數。

該測試被稱為Fermat測試。需要注意的是:Fermat測試不一定是準確的,有可能出現把合數誤判為質數的情況。

Miller和Rabin在Fermat測試上,建立了Miller-Rabin質數測試演算法。

與Fermat測試相比,增加了一個二次探測定理:

如果p是奇素數,則 x^2 ≡ 1(mod p)的解為 x ≡ 1 或 x ≡ p - 1(mod p)

如果a^(n-1) ≡ 1 (mod n)成立,Miller-Rabin演算法不是立即找另一個a進行測試,而是看n-1是不是偶數。如果n-1是偶數,另u=(n-1)/2,並檢查是否滿足二次探測定理即a^u ≡ 1 或 a^u ≡ n - 1(mod n)。

舉個Matrix67 Blog上的例子,假設n=341,我們選取的a=2。則第一次測試時,2^340 mod 341=1。由於340是偶數,因此我們檢查2^170,得到2^170 mod 341=1,滿足二次探測定理。同時由於170還是偶數,因此我們進一步檢查2^85 mod 341=32。此時不滿足二次探測定理,因此可以判定341不為質數。

將這兩條定理合起來,也就是最常見的Miller-Rabin測試。

但一次MR測試仍然有一定的錯誤率。為了使我們的結果儘可能的正確,我們需要進行多次MR測試,這樣可以把錯誤率降低。

寫成虛擬碼為:

Miller-Rabin(n):
	If (n <= 2) Then
		If (n == 2) Then
			Return True
		End If
		Return False
	End If
	
	If (n mod 2 == 0) Then
		// n為非2的偶數,直接返回合數
		Return False
	End If
	
	// 我們先找到的最小的a^u,再逐步擴大到a^(n-1)
	
	u = n - 1; // u表示指數
	while (u % 2 == 0) 
		u = u / 2
	End While // 提取因子2
	
	For i = 1 .. S // S為設定的測試次數
		a = rand_Number(2, n - 1) // 隨機獲取一個2~n-1的數a
		x = a^u % n
		While (u < n) 
			// 依次次檢查每一個相鄰的 a^u, a^2u, a^4u, ... a^(2^k*u)是否滿足二次探測定理
			y = x^2 % n 
			If (y == 1 and x != 1 and x != n - 1)	// 二次探測定理
				// 若y = x^2 ≡ 1(mod n)
				// 但是 x != 1 且 x != n-1
				Return False
			End If
			x = y
			u = u * 2 
		End While
		If (x != 1) Then	// Fermat測試
			Return False
		End If
	End For
	Return True

值得一提的是,Miller-Rabin每次測試失誤的概率是1/4;進行S次後,失誤的概率是4^(-S)。

小Hi:那麼小Ho,你能計算出這個演算法的時間複雜度麼?

小Ho:恩,每一次單獨的MR測試,需要O(log n)的時間。一共要進行S次MR測試,也就是O(Slog n)。

小Hi:沒錯,這樣就能夠在很短的時間內完成質數的測試了。當然如果你還是不放心,可以把S的值設定的更高一點。

小Ho:好!這樣就能夠順利的找到大質數了。

本題的提示參考了Matrix67的Blog和wikipedia的詞條。

Matrix67的Blog有更多的細節描寫。Wiki中的虛擬碼比上文中的簡潔一些,並且有介紹了一些小技巧:比如如果n<2^64(n<1e18),只用選取a=2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37做測試即可


以上