米勒羅賓素數檢測(Miller-Rabin)

適用範圍:較大數的較快素性判斷

思路:

由於有好的文章講解具體原理(見參考文章),這裏只是把代碼的大體思路點一下,讀完了文章若是還有些迷糊,能夠參考如下解釋html

原理是費馬小定理:若是p是素數,則a^(p-1)%p==1,加上二次探測定理:若是p是一個素數,則x^2%p==1的解爲,則x=1或者x=n-1。ios

由於有經過費馬小定理的僞素數的機率不是充分小,在此基礎上加以改進判斷。c++

一次檢測中:web

主要是把一個數n的n-1分解成d*2^r的形式,其中d爲奇數,正向過程是a^n%p若是是1,就繼續分解a^(n/2)%p,(a爲一個與n互素的數)看是否爲1,;若是是n-1就中止分解,說明至此沒法判斷是否爲素數;若是不等於這兩個值,則必定爲合數。而在寫代碼過程是這個過程的逆向過程,先分解到底,看最後這個a^d%p是否爲1或n-1,若是是說明已經分解到底了,也就是經過了這次素性測試。若是不是,說明在正向過程當中出現了要麼a的某次方爲n-1,根據算法中止了檢測過程;要麼就是中間的某一個結果不等於這兩個數,那麼就是合數。就從最後往前面推,每一步看滿不知足上述條件。直到判斷爲合數或者終止檢測的那一步。算法

屢次檢測過程:dom

不停更換a測試。函數

代碼:(代碼中可能須要用到快速冪和大數乘積取餘,能夠參考前一篇博客)

 1 #include <iostream>
 2 #include <time.h>
 3 using namespace std;
 4 long long an[] = {2,3,5,7,11,13,17,61};
 5 long long Random(long long n)//生成0到n之間的整數
 6 {
 7     return (double) rand()/RAND_MAX*n+0.5;//(doubel)rand()/RAND_MAX生成0-1之間的浮點數
 8 }
 9 long long q_mod(long long a,long long n,long long p)
10 {
11     a = a%p;
12     //首先降a的規模
13     long long sum = 1;//記錄結果
14     while(n)
15     {
16         if(n&1)
17         {
18             sum = (sum*a)%p;//n爲奇數時單獨拿出來乘
19         }
20         a = (a*a)%p;//合併a降n的規模
21         n /= 2;
22     }
23     return sum;
24 }
25 long long q_mul(long long a,long long b,long long p)
26 {
27     long long sum = 0;
28     while(b)
29     {
30         if(b&1)//若是b的二進制末尾是零
31         {
32             (sum += a)%=p;//a要加上取餘
33         }
34         (a <<= 1)%=p;//不斷把a乘2至關於提升位數
35         b >>= 1;//把b右移
36     }
37     return sum;
38 }
39 bool witness(long long a,long long n)
40 {
41     long long d = n-1;
42     long long r = 0;
43     while(d%2==0)
44     {
45         d/=2;
46         r++;
47     }//n-1分解成d*2^r,d爲奇數
48     long long x = q_mod(a,d,n);
49     //cout << "d " << d << " r " << r << " x " << x << endl;
50     if(x==1||x==n-1)//最終的餘數是1或n-1則多是素數
51     {
52         return true;
53     }
54     while(r--)
55     {
56         x = q_mul(x,x,n);
57         if(x==n-1)//考慮開始在不斷地往下餘的過程
58         {
59             return true;//中間若是有一個餘數是n-1說明中斷了此過程,則多是素數
60         }
61     }
62     return false;//不然若是中間沒有中斷但最後是餘數又不是n-1和1說明必定不是素數
63 }
64 bool miller_rabin(long long n)
65 {
66     const int times = 50;//試驗次數
67     if(n==2)
68     {
69         return true;
70     }
71     if(n<2||n%2==0)
72     {
73         return false;
74     }
75     for(int i = 0;i<times;i++)
76     {
77         long long a = Random(n-2)+1;//1到(n-1)
78         //cout << a << endl;
79         if(!witness(a,n))
80         {
81             return false;
82         }
83     }
84     return true;
85 }
86 int main()
87 {
88     long long num;
89     cin >> num;
90     if(miller_rabin(num))
91     {
92         cout << "Yes" << endl;
93     }
94     else
95     {
96         cout << "No" << endl;
97     }
98 }

 

參考文章:

Matrix67,數論部分第一節:素數與素性測試,http://www.matrix67.com/blog/archives/234(原理只推薦這一篇,這一篇是我目前見到的解釋的最清晰,也多是最精彩的,沒有之一!雖然是07年的,好博客與時間沒有關係)測試

由於上篇代碼部分用的是Pascal,這裏找到c++的代碼版本:spa

StanleyClinton,素數斷定Miller_Rabin算法詳解,https://blog.csdn.net/maxichu/article/details/45458569.net

還有rand函數的使用:https://jingyan.baidu.com/article/e73e26c060bdbc24adb6a7b0.html

相關文章
相關標籤/搜索