// is a^(n-1) = 1 (mod n) boolwitness(ll a, ll n){ ll u = n - 1, t = 0; while (u & 1 == 0) u >>= 1, t++; // n - 1 = 2^t * u
ll x = modular_exponentiation(a, u, n); // 二次探测定理 // 如果一个数p是质数,对于一个x∈(0,p)且x∈Z,方程x^2≡1(modp)的解有且只有两个:x=1或x=p−1。 for (int i = 0; i < t; i++) { int xp = x; x = x * x % n; if (x == 1 && xp != 1 && xp != n - 1) returntrue; } if (x != 1) returntrue; returnfalse; }
// test n times a^(n-1) = 1 (mod n), rand a boolmiller_rabin(ll n, ll s){ for (int i = 0; i < s; i++) { ll a = time(NULL) * (ll)rand() % (n - 1) + 1; // cout << "a " << a << "n " << n << endl; if (witness(a, n)) returnfalse; } returntrue; }
反复平方法求数的幂
求$a^{b}\pmod {n}$的高效算法,时间复杂度$O(logb)$
1 2 3 4 5 6 7 8 9 10
ll modular_exponentiation(ll a, ll b, ll n){ ll rt = 1; while (b) { if (b & 1) rt = rt * a % n; a = a * a % n; b >>= 1; } return rt; }
#include<algorithm> #include<cstdio> #include<cstdlib> #include<ctime> #include<iostream> #define ll long long usingnamespace std; #define print(a, b) cout << a << ": " << b << endl
// extend eculid , d = gcd(a,b) = ax+by voidex_gcd(ll a, ll b, ll* d, ll* x, ll* y){ if (b == 0) { *d = a; *x = 1; *y = 0; } else { ex_gcd(b, a % b, d, x, y); ll t = *x; *x = *y; *y = t - (a / b) * (*y); } }
// a^b%n ////a<n a*n < MAX n*n < MAX ll modular_exponentiation(ll a, ll b, ll n){ ll rt = 1; while (b) { if (b & 1) rt = rt * a % n; a = a * a % n; b >>= 1; } return rt; }
// is a^(n-1) = 1 (mod n) boolwitness(ll a, ll n){ ll u = n - 1, t = 0; while (u & 1 == 0) u >>= 1, t++; // n - 1 = 2^t * u
ll x = modular_exponentiation(a, u, n); // 二次探测定理 // 如果一个数p是质数,对于一个x∈(0,p)且x∈Z,方程x^2≡1(modp)的解有且只有两个:x=1或x=p−1。 for (int i = 0; i < t; i++) { int xp = x; x = x * x % n; if (x == 1 && xp != 1 && xp != n - 1) returntrue; } if (x != 1) returntrue; returnfalse; }
// test n times a^(n-1) = 1 (mod n), rand a boolmiller_rabin(ll n, ll s){ for (int i = 0; i < s; i++) { ll a = time(NULL) * (ll)rand() % (n - 1) + 1; // cout << "a " << a << "n " << n << endl; if (witness(a, n)) returnfalse; } returntrue; }
// rand big prime in 2^15 ll rand_prime(ll rd){ ll prime = time(NULL) * rd % (2LL << 15); while (!miller_rabin(prime, 10)) { prime++; // cout << prime << endl; } return prime; }