素數判定的一些討論(Miller-Rabin演算法)
阿新 • • 發佈:2019-01-31
很久沒有寫部落格了。。。最近軍訓加開學,感覺刷題速度有降低,要補一補。
迴歸正題,正式進入數論階段,討論一下關於素數判定的那些事。
一類問題: 判定一個整數n(n>1)是否為素數。
演算法1:
直接根據素數的定義列舉n%i==0
時間複雜度:
bool is_prime(int n) {
int i;
for(i = 2; i < n; i++)
if(n % i == 0) return false;
return true;
}
演算法2:
發現若存在n%i==0
n%(n/i)==0
。 所以只需列舉
時間複雜度:
bool is_prime(int n) {
int i;
for(i = 2; i * i <= n; i++)
if(n % i == 0) return false;
return true;
Miller-Rabin演算法:
這是一種隨機性素數判定演算法,也就是說,答案可能出錯,但是可能性極小。
先是講兩個定理:
費馬小定理:
對於一個質數
二次探測定理:
對於 <x<p
的解為:
因為費馬小定理的逆命題不成立,而否逆命題成立,所以我們可以利用一下一點:
對於任意整數
所以我們可以不斷在區間
但是這還不夠精確,我們可以先把 [i]
注意以上操作中所有的形如
這就是Miller-Rabin演算法的主要內容。
時間複雜度:考慮常數後為
程式碼如下:
const int MAXN = 65;
long long n, x[MAXN];
long long multi(long long a, long long b, long long p) {
long long ans = 0;
while(b) {
if(b&1LL) ans = (ans+a)%p;
a = (a+a)%p;
b >>= 1;
}
return ans;
}
long long qpow(long long a, long long b, long long p) {
long long ans = 1;
while(b) {
if(b&1LL) ans = multi(ans, a, p);
a = multi(a, a, p);
b >>= 1;
}
return ans;
}
bool Miller_Rabin(long long n) {
if(n == 2) return true;
int s = 20, i, t = 0;
long long u = n-1;
while(!(u & 1)) {
t++;
u >>= 1;
}
while(s--) {
long long a = rand()%(n-2)+2;
x[0] = qpow(a, u, n);
for(i = 1; i <= t; i++) {
x[i] = multi(x[i-1], x[i-1], n);
if(x[i] == 1 && x[i-1] != 1 && x[i-1] != n-1) return false;
}
if(x[t] != 1) return false;
}
return true;
}