Miller-Rabin算法用於檢測一個數n是不是素數。其時間複雜度上界爲O(klog2(n)),其中k爲檢測的輪數。增大k能夠提升Miller-Rabin算法的準確度。算法
要檢測一個數是否爲素數,簡單的算法有兩種,第一種是對2~√n之間的數,檢查其是不是n的因子,其時間複雜度爲O(√n)。第二種就是打表法,利用歐拉篩能夠在O(N)的時空複雜度內獲取1~N之間的全部素數並存儲。不管是哪一種狀況,對於超大的n,都要消耗可怕的時間來進行判斷,譬如取n爲1e18,這樣兩種算法在現代計算機上都是沒法結束的(後者會直接內存不足)。測試
數論中的費馬小定理中指出,對於任意素數p,以及對於模p的剩餘類環{1,2,...,p-1}中的任意數x,都知足x^p=x(mod p)。所以咱們能夠用這個小小的技巧來排除大量的合數。譬如對於素數5,咱們發現2^5(mod 5)=2,而對於6,有2^6(mod 6)=4。spa
可是費馬小定理中p是素數是x^p=x(mod p)的充分條件,而非必要條件,好比4^6=4(mod 6),但咱們不能說6是素數。所以咱們須要從模p的剩餘類環中選取更多的數進行測試,以加強結果的可信度,只要存在一個數x不知足x^p=x(mod p),那麼p就毫不多是素數。可是仍是存在一類極端的合數p,使得對於任意1,..,p-1中的x都知足x^p=x(mod p),這類合數稱爲Carmichael數,一個例子就是561。因爲這類數的存在,使得咱們用費馬小定理徹底沒法正確判定一個數爲素數仍是合數。code
而Miller-Rabin算法的出世使得至關一類的知足費馬小定理的合數沒法經過素數測試。Miller-Rabin算法基於一個事實,若x^2=1(mod p),那麼若p是素數,則(x-1)(x+1)=0(mod p),除非p爲2,不然(x-1)與(x+1)在模p的性質下是不相等的,不管p是否爲2,均可以保證有(x-1)=0(mod p)或者(x+1)=0(mod p)(由於模p剩餘類環是整環),即x=1或x=p-1。所以咱們能夠在p經過數x的費馬測試後,即x^p=p(mod p),也能夠寫做x^(p-1)=1(mod p),若p-1是偶數,那麼能夠繼續經過x^((p-1)/2)是否等於1或(p-1)來進行測試。若是測試經過還能夠繼續判斷是否知足x^2k=1(mod p),從而繼續進行判斷。只要一環判斷不經過,那麼就保證p是合數。blog
看一下咱們方纔提過的Carmichael數561,進行Miller-Rabin測試:內存
2^560=1(mod 561) 知足模板
2^280=1(mod 561) 知足class
2^140=67(mod 561) 不知足
下面給出我我的使用的MR算法的模板:循環
mr(p) if(p == 2 || p == 3 || p == 5 || p == 7) return true return mr0(2, p) && mr0(3, p) && mr0(5, p) && mr0(7, p) mr0(x, p) if (x^(p-1)) % p != 1 return false k = p - 1 while k % 2 == 0 k = k / 2 t = x^k if(t != 1 && t != p - 1) return false if(t == p - 1) return true return true
因爲mr0中的冪運算能夠利用快速冪乘法的技術來實現,所以一次冪運算的時間複雜度爲O(log2n),而while循環最多執行log2(p)次,每次循環執行一次冪乘運算,故總的時間複雜度爲O((log2p)^2)。技巧