1. 程式人生 > >Miller-Rabin演算法

Miller-Rabin演算法

寫在前面:

  記錄了個人的學習過程,同時方便複習

  整理自網路

  非原創部分會標明出處

 

by blackgryph0n

 

目錄

 

 

結論

  Miller-Rabin演算法可以在O(k log2(n))的時間內檢測一個超級大的正整數n是否是素數,k為自己設定的檢測的次數

 

證明

  [◹]費馬-尤拉定理

  對於任意素數p,以及對於模p的剩餘類環{1,2,...,p-1}中的任意數x,都滿足xp

 ≡ x (mod p)

  [◹]快速冪

  p是素數為xp ≡ x (mod p)的充分不必要條件

  但是仍然可以用這個技巧來排除大量的合數

  為了排除大量合數,我們需要從模p的剩餘類環中選取更多的數進行測試,以增強結果的可信度,即二次探測定理,只要存在一個數x不滿足xp ≡ x (mod p),那麼p就絕不可能是素數

 

拓展

  然而某些合數模p的剩餘類環中,對於任意1,..,p-1中的x都滿足xp ≡ x (mod p),這類合數稱為卡邁克爾(Carmichael)數

  Carmichael數是比較少的,在1~100000000範圍內的整數中,只有255個

  In number theory, a Carmichael number is a composite number n which satisfies the modular arithmetic congruence relation bn-1 ≡ 1 (mod n) for all integers b which are relatively prime to n

 

  They are named for Robert Carmichael. The Carmichael numbers are the subset K

1 of the Knödel numbers

  Equivalently, a Carmichael number is a composite number bn ≡ b (mod n) for which  for all integers b

——Wikipedia

 

常見卡邁克爾數:

561

1105

1729

2465

2821

6601

8911

10585

15841

……

——bia度百科

  裸的Miller-Rabin演算法不能夠篩除這樣的合數

 

實現

上程式碼:

C++:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 
 6 int const times=10;
 7 
 8 ll ponyFE(ll a,ll b,ll c)
 9 {
10     ll ans=1;
11     a%=c;
12     while(b!=0)
13     {
14         if(b&1) ans=(ans*a)%c;
15         b>>=1;
16         a=(a*a)%c;
17     }
18     return ans;
19 }
20 
21 bool millerRabin(ll x)
22 {
23     if(x==2) return 1;
24     if(!(x&1)||x==1) return 0;
25     
26     bool pass;
27     ll d=x-1,m;
28     while(!(d&1)) d>>=1;ll tmp=d;
29     for(int i=1;i<=times;++i)
30     {
31         d=tmp;pass=0;
32         
33         m=ponyFE(rand()%(x-2)+2,d,x);
34         if(m==1) continue;
35         else for(;d<x&&d>=0;m=(m*m)%x,d<<=1)
36             if(m==x-1){pass=1;break;}
37         
38         if(!pass) return 0;
39     }
40     
41     return 1;
42 }
43 
44 int main(int argc,char *argv[],char *enc[])
45 {
46     int tot=0;
47     for(ll i=1;i<=100;++i)
48         if(millerRabin(i)) printf("%d\n",i),++tot;    
49     printf("tot:%d\n",tot);
50     
51     return 0;
52 }

Java:

 1 import java.io.*;
 2 import java.util.*;
 3 
 4 class Pony
 5 {
 6     static int times=10;
 7 
 8     static long ponyFE(long a,long b,long c)
 9     {
10         long ans=1;
11         a%=c;
12         while(b!=0)
13         {
14             if((b&1)==1) ans=(ans*a)%c;
15             b>>=1;
16             a=(a*a)%c;
17         }
18         return ans;
19     }
20 
21     static boolean millerRabin(long x)
22     {
23         if(x==2) return true;
24         if((x&1)==0||x==1) return false;
25         
26         boolean pass;
27         long d=x-1,m;
28         while((d&1)==0) d>>=1;long tmp=d;
29         for(int i=1;i<=times;++i)
30         {
31             d=tmp;pass=false;
32 
33             m=ponyFE((int)(Math.random())%(x-2)+2,d,x);
34             if(m==1) continue;
35             else for(;d<x&&d>=0;m=(m*m)%x,d<<=1)
36                 if(m==x-1){pass=true;break;}
37         
38             if(!pass) return false;
39         }
40         
41         return true;
42     }
43 
44     public static void main(String[] args) throws Exception
45     {
46         Scanner cin=new Scanner(System.in);
47 
48         int tot=0;
49         for(long i=1;i<=100;++i)
50             if(millerRabin(i))
51             {
52                 System.out.println(i);
53                 ++tot;
54             }
55         System.out.println("tot:"+tot);
56     }
57 }