1. 程式人生 > >淺談基於隨機性演算法的素數判定

淺談基於隨機性演算法的素數判定

引:考慮這樣的一個問題

判斷一個long long範圍內的數是否是素數。

引理1-1:

apa(modp)|(a,p)=1
其實這就是熟悉的Fermat小定理了~~

引理1-2:
對於

a21(modn)|n
的解僅有 a = 1 或 a = n - 1
顯然原式 = (a mod n) * (a mod n)
所以當且僅當 a mod n = 1 或 a mod n = -1 時有解, 那麼顯然~~~

下面介紹一種基於隨機演算法的Miller-Robin演算法
1.將n - 1分解成 2 ^ q * m 的形式
2.若n為大於2的素數,則必定存在 a < n 使得 a ^ (n-1) mod n = 1
3.先隨機取一個a,計算 a ^ m ,然後再在 a ^ m 的基礎上不停地平方,並使得 a 的指數小於等於 n - 1, 若a ^ (n-1) mod n = 1, 則在這個過程中必然會算出某個值同餘 n 為 1,我們就找到了答案。
4.注意進行多重判斷(多選幾個a)。

下面是程式碼(poj 1811):

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
typedef long long LL;
const LL INF = 1LL << 60;

#define debug(...) fprintf(stderr, __VA_ARGS__)

LL gcd(LL a, LL b) { 
    if(a > b) swap(a, b);
    return
a == 0 ? b : gcd(b % a, a); } LL Mul(LL n, LL m, LL p) { LL ans = 0; for(LL i = 1; i <= m; i <<= 1LL, n = (n + n) % p) if(i & m) ans = (ans + n) % p; return ans; } LL Pow(LL n, LL m, LL p) { LL ans = 1; n %= p; while(m > 0LL) { if(m & 1LL) ans = Mul(ans, n, p); n = Mul(n, n, p); m >>= 1L
L; } return ans; } bool isprime(LL n, LL t) { if(n == 2 || n == 3) return true; if(n < 2 || (n & 1LL) == 0) return false; LL m = n - 1, q = 0; while((m & 1LL) == 0) { q++; m >>= 1LL; } for(LL i = 0; i < t; i++) { LL a = rand() % (n - 1) + 1; LL x = Pow(a, m, n), y; for(LL j = 0; j < q; j++) { y = Mul(x, x, n); if(y == 1 && x != 1 && x != n - 1) return false; x = y; } if(x != 1) return false; } return true; } LL Min; void Pollcard_Rho(LL n) { //debug("%lld\n", n); if(isprime(n, 40)) { Min = min(Min, n); return; } while(1) { LL x = rand() % (n - 1) + 1; LL c = rand() % (n - 1) + 1; for(LL y = x, i = 2, j = 2; ; i++) { x = (Mul(x, x, n) + c) % n; LL z = (y - x) % n; if(z < 0) z = -z; LL d = gcd(z, n); if(d > 1 && d < n) { Pollcard_Rho(d), Pollcard_Rho(n / d); return; } if(x == y) break; if(i == j) y = x, j <<= 1; } } } LL n, T; int main() { #ifndef ONLINE_JUDGE freopen("data.txt", "r", stdin); freopen("ans.txt", "w", stdout); #endif srand(67); scanf("%lld", &T); while(T--) { scanf("%lld", &n); if(isprime(n, 40)) puts("Prime"); else { Min = INF; Pollcard_Rho(n); printf("%lld\n", Min); } } return 0; }

題中還涉及到了另一個基於隨機性的因數分解(其實就是一個瞎逼亂搞神奇演算法, 時間複雜度 O(玄學))。