隨機素數法

2021-07-09 04:34:09 字數 3385 閱讀 8119

在介紹素數測試相關演算法之前,先要引入尤拉定理和費馬定理。

尤拉定理:對於任意的整數n>1,a^φ(n)  ≡1(mod n)對所有的a∈z*n都成立。

其中φ(n)為z*n的規模。φ(n)=n∏(1-1/p).可以理解成初始有一張的表,然後對每個能整除n的p,在表中刪除p的倍數後剩下的數。z*n定義為中與n互質的元素。例如:z*14=,φ(14)=5。

我們考慮的乙個已知元素a對模n的倍數,,考慮對模a的冪組成的序列,其中a∈z* n:  

a0,a1,a2,a3,……

模n.第i個數為ai mod n.

例如:對模7,3的冪為

i                0    1    2    3    4    5    6    7……

3^i % 7     1     3    2    6    4    5    1    3……

則z*7中,<3>=,則φ(7)=6同樣可以得到<1>=,<2>=.

由尤拉定理我們可以從而得出費馬定理,他是尤拉定理的特殊表現。

費馬定理:如果p是素數,則a^(p-1)  ≡1(mod p)對所有的a∈z*p都成立。

當p為素數時,他的因子只有p和1. 根據φ(n)=n∏(1-1/p):

φ(p)=p(1-1/p1)..(1-1/pn)=p-1

由尤拉定理即可驗證費馬定理的正確性。

對於素數測試有一種簡便的方法,我們稱之為試除法。就是我們用2到sqrt(n)分別去除n,每次的試除需要常數時間,最壞的情況需要的時間是⊙(sqrt(n)),n為長度。所以只有n很小或者n有小因子的時候該演算法才能較快的執行。

下面介紹一種效率較高的演算法,miller-rabin隨機素數測試法。他是對於偽素數的改進。

所謂偽素數的定義為:z+ n表示z n中的非零元素:

z+ n=

如果n是乙個合數,且滿足  an-1≡1(mod n)則說n是基於a的偽素數。例如:341,561(基於2)。

根據費馬定理如果p是素數,則ap-1  ≡1(mod p)對所有的a∈z*p都成立。

我們可以思考,如果要判斷乙個數p是素數,那麼我們是不是只要隨機找乙個a其中p>a>1,如果a^p-1  ≡1(mod p),那麼p有可能是素數了。如果對所有的a∈z*p都成立,那麼p必然是素數。反過來若發現存在乙個a∈z*p 使得ap-1  !≡1(mod p)則p必然不是素數。我們的這個演算法的思想就是使用隨機的a去探測是否存在這樣的乙個a使得a^(p-1)  !≡1(mod p),如果存在這樣的a,那麼就皆大歡喜,你已經證明了他不是素數了。如果沒找到,那麼他極有可能是素數了,但不一定是。

偽**:

pseudoprime(n)

1        if(an-1mod n!≡1)

2                return composite.  

3        else return prime.

該過程如果結果為composite則可以認定n不為素數。如果結果返prime則極大可能為素數。如果判定為合數結果總是正確的。如果判定為素數的話,只有當n是基於a的偽素數才會出錯。這個過程出錯的機率相當的小,選取512位數,基於2的偽素數概率不到1/1020.在實際的操作中幾乎永遠不會出錯。

miller-rabin隨機素數測試法對偽素數測試過程進行了兩方面的改進:

第一:他實驗了數個隨機選取的a進行試驗。

第二:當計算每個模取冪的值時,注意在最後一組平方里是否發現了對模n來說1的非平方根。如果存在,終止並輸出pomposite.

下面證明第二點:

定理:如果p是乙個奇素數且e≥1.則方程

x2≡1(mod pe)

僅有兩個解: x1=1和x2=-1。

由定理可以得出推論:如果對模n存在1的非平凡平方根,則n是合數。(平凡平方根為1或-1)。因此檢測非平凡平方根的存在可以有效的判斷n是合數。把它運用與miller-rabin素數測試過程。令n-1=2tu,其中t≥1且u是奇數;亦即,n-1的二進位制表示是奇數u的二進位制後面跟上t個零。例如n=13,n-1的二進位制為1100,則t=2,u=3.因此,an-1≡(a u)2^t,所以可以通過先計算a u mod n,然後對結果連續平方t次來計算an-1 mod n。

偽**:

witness(a,n)

1        let n-1=2tu,where t≥1 and u is odd

2        x0=au mod n

3        for i←1 to t

4               do xi=x2 i-1 mod n

5                     if  xi=1 and x i-1≠1and x i-1≠n-1

6                          then return true

7        if(xt≠1)

8               then return true

9        return false

該演算法通過第2行計算x0=au mod n。3到6行對結果進行t次平方,計算出an-1 mod n.

5到6行進行非平凡平方根的檢測,如發現非平凡平方根則證明是合數,返回true。第7到8行為檢測an-1 mod n是否為1,如果發現不為1則不滿足素數an-1 mod n≡1,證明n是合數返回true,若沒發現能證明n是合數的證據,則將會執行到第9行結束返回false.

多次試驗可以有效的降低錯誤率的發生。例如:當a=2時561是偽素數,他將被當做素數處理。而在a=7的情況下,a560≡241(mod 561)因此a=7可以證明561為合數。

偽**:

miller-rabin(n,s)

1for i=1 to s

2   do a=random(1,n-1)

3        if witness (a,n)

4             the return composite//確定為合數

5 return prime

第1到4行進行s次實驗,取a為1到n-1之間的隨機數。第三行進行判斷是否存在乙個值能證明n是合數,如果返回值為true說明找到了n為合數定的證據,n必然是合數。返回false找不到,則說明n極大可能是乙個素數。

miller rabin是乙個運氣演算法。他出錯的概率與你選擇的s的大小以及隨機數a取到的值有關。只有當運氣太差,在主迴圈s次迭代中,每一次都沒能發現n為合數的證據時,才會出錯,每次都錯過發現證據的概率至多為2-s,在實際執行中出錯的機率是相當低的。 附:

int

witness(

inta,

intn)

return

(d ==1?

0: 1);

}int

miller(

intn,

ints =50

)return1;

}

又見素數(素數篩法)

又見素數 time limit 2000ms memory limit 65536k total submit 287 accepted 24 description 給定乙個正整數n n 10000000 求n 包含 以內素數的個數。input 第一行為乙個整數t t 1000 表示測試資料的組數...

素數篩法求素數

素數篩類似於打表標記,預先處理掉非素數的數,即素數的倍數 任意非素數都可以由幾個素數相乘得到 於是效率比暴力求解快得多。埃氏篩法的效率為o n loglog n 簡單易懂,但是會重複標記,比如當i為2時,6會被標記掉,然而當i為3時,6又會被重複標記,這樣的重複訪問加大了時間複雜度,於是有了尤拉篩。...

驗證素數(素數篩選法驗證素數)

本來是在做容斥原理的題,既然碰到求a b內與n互質的數的個數,就順便將與素數相關的知識整理一遍。1 輸入數n,判斷是否為素數的一般方法 includeusing namespace std int main cout includeusing namespace std int main cout ...