其基于以下两个定理。
Fermat小定理
若n是素数,则 ∀ a ( a ̸ ≡ 0 ( m o d n ) ) \forall a(a \not\equiv 0 \pmod{n}) ∀a(a̸≡0(modn)),有 a n − 1 ≡ 1 ( m o d n ) a^{n-1} \equiv 1 \pmod{n} an−1≡1(modn).
二次探测定理
若n是素数,则 x 2 ≡ 1 ( m o d n ) x^2 \equiv 1 \pmod{n} x2≡1(modn)只有平凡根 x = ± 1 x=\pm1 x=±1,即 x = 1 , x = n − 1 x=1,x=n-1 x=1,x=n−1.
费马小定理鼎鼎有名,而二次探测定理由 Z p Z_p Zp是域,域中无零因子容易得到。
注意这两个定理都是叙述了素数的必要条件,而Miller-Rabin对于要检验的n,是选取若干个a,检验是否满足这两个必要条件。显然,如果某个必要条件不满足,那么断言不是素数是正确的。但是,选了好几个a,都满足这两个必要条件,n是质数还是合数是无法确定的,但是Miller-Rabin算法选择忽略这一点,直接断言n是素数。
换句话说,Miller-Rabin算法断言一个数不是素数一定是正确的,断言一个数是素数,则可能是错误的。但是,实际上,会被误判为素数的合数,是很少的。而且每选取一个符合条件的a,通过检验出错的概率不超过 1 2 \frac{1}{2} 21.因此实际应用中使用Miller-Rabin算法是可行的。
实际上,选取一个a,仅仅基于费马小定理给出的必要条件做断言的检测算法,被错误断言为素数的合数称作基于a的伪素数。
而通过选取各个符合条件的a,仅仅基于费马小定理,进行断言的检测算法,被错误断言为素数的伪素数就是卡迈克尔数。
假设 n n n是奇数,令 n = m × 2 q ( q ≥ 1 ) n=m \times 2^q (q \geq 1) n=m×2q(q≥1),其中 m m m是奇数.
对于序列 a m   m o d   n , a 2 m   m o d   n , a 4 m   m o d   n , … , a 2 q × m   m o d   n a^m \bmod n, a^{2m} \bmod n, a^{4m} \bmod n,\ldots,a^{2^q \times m} \bmod n ammodn,a2mmodn,a4mmodn,…,a2q×mmodn.
最后一项就是费马小定理中的 a n − 1 a^{n-1} an−1, 并且每一项都是前一项的平方。
我们一项一项往后计算。
若当前项为1,后面每一项显然都是1。而根据二次探测定理,n是素数必须前面一项是1或n-1.如果不符合,断言不是素数;符合,断言是素数。
若当前项不是1,暂时不断言,接着往后算。除非当前是最后一项了,那么断言不是素数。
当然,如果第一项是1,由于不存在二次探测的方程,所以不检验前面一项(或者认为前面一项符合条件)。
使用了快速幂模和快速幂加模板mod_sys。下面代码只是miller-rabin核心代码。
// 如果只是int范围内,可以将pow_v2改为pow,mlt改为普通乘法
bool miller_rabin(ll a, ll n, ll q, ll m, mod_sys& mod) {
a = mod.pow_v2(a, m);
bool is_ordinary = true;
for (int i = 0; i < q; ++i) {
if (a == 1) {
return is_ordinary;
} else {
is_ordinary = (a == n-1);
a = mod.mlt(a,a);
}
}
return (a==1)&&(is_ordinary); // 最后一项
}
// 使用miller_rabin检测是否是素数
const int kCheckCnt = 8;
// 为了随机数
random_device rd;
mt19937_64 gen(rd());
bool miller_rabin(ll n) {
if (n == 2) return true;
if ((n <= 2) || (n&1^1)) return false;
// 2^q×m表示原本输入的n-1
ll m = n, q = 0;
do { m >>= 1; ++q; } while(m&1^1);
// 随机数生成,[1,n-1] 均匀分布
uniform_int_distribution<> dis(1, n-1);
mod_sys mod;
mod.set_mod(n);
for (int i = 0; i < kCheckCnt; ++i)
if (!miller_rabin(dis(gen), n, q, m, mod))
return false;
return true;
}
模板题推荐hdu2138