【学习笔记】Miller-Rabin(米勒-拉宾)素性测试,附常用表

@TOC

素性测试是检验一个给定的整数是否为素数的测试。

最简单的就是用 n \sqrt{n} n 以内的数去试除。这是确定性的算法,即能准确知道 n n n 是否为质数。

但今天学习的是一种随机算法。

Fermat 小定理

如果 p p p 是一个质数,且 a % p ≠ 0 a\%p≠0 a%p=0,则有 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1\pmod p ap11(modp)

利用 Fermat定理 可以得到一个测试合数的有力算法:对 n > 1 n>1 n>1,选择 a > 1 a>1 a>1, 计算 a n − 1 m o d    n a^{n-1} \mod n an1modn

  • 若结果 ≠ 1 \neq 1 =1,则 n n n 是合数。

  • 若结果 = 1 =1 =1, 则 n n n 可能是素数,并被称为一个以 a a a 为基的弱可能素数 (a-PRP) 。

    n n n 是合数,则又被称为一个以 a a a 为基的伪素数。

这个算法的成功率是相当高的。在 < 25000000000 <25000000000 <25000000000 1091987405 1091987405 1091987405 个素数中,一共只有 21853 21853 21853 个以 2 2 2 为基的伪素数。

但不幸的是,存在无穷多个被称为 Carmichael数(卡迈克尔数)的整数,对于任意与其互素的整数 a a a 算法的计算结果都是 1 1 1

最小的五个 Carmichael数 561 、 1105 、 1729 、 2465 、 2801 561、1105、1729、2465、2801 5611105172924652801

miller_rabin(米勒-拉宾)素性测试

定理 :如果 p p p 是个 > 2 >2 >2 的质数,则方程 x 2 ≡ 1 ( m o d p ) x^2\equiv 1\pmod p x21(modp) 的解只有 x = ± 1 x=±1 x=±1

证明:

x 2 ≡ 1 ( m o d p ) ⇒ x 2 − 1 ≡ 0 ( m o d p ) ⇒ ( x + 1 ) ( x − 1 ) ≡ 0 ( m o d p ) x^2\equiv 1\pmod p\Rightarrow x^2-1\equiv 0\pmod p\Rightarrow (x+1)(x-1)\equiv 0\pmod p x21(modp)x210(modp)(x+1)(x1)0(modp)

p ∣ ( x + 1 ) ∧ p ∣ ( x − 1 ) p|(x+1)\wedge p|(x-1) p(x+1)p(x1)。则一定存在两个数 j , k j,k j,k,使得 x + 1 = j p , x − 1 = k p x+1=jp,x-1=kp x+1=jp,x1=kp,两式相减 2 = ( k − j ) p 2=(k-j)p 2=(kj)p,不可能。

所以只可能是 p ∣ ( x + 1 ) ∨ p ∣ ( x − 1 ) p|(x+1)\vee p|(x-1) p(x+1)p(x1)

p ∣ ( x + 1 ) p|(x+1) p(x+1),则 x + 1 = k p ⇒ x ≡ − 1 ( m o d p ) x+1=kp\Rightarrow x\equiv -1\pmod p x+1=kpx1(modp)

p ∣ ( x − 1 ) p|(x-1) p(x1),则 x − 1 = k p ⇒ x ≡ 1 ( m o d p ) x-1=kp\Rightarrow x\equiv 1\pmod p x1=kpx1(modp)

以上定理的逆否命题:当方程 x 2 ≡ 1 ( m o d p ) x^2\equiv 1\pmod p x21(modp) 有一个解 x ≠ − 1 ∧ x ≠ 1 x\neq-1\wedge x\neq 1 x=1x=1,则 p p p 一定不是质数。

miller_rabin 是一个质数判断算法,采用随机算法能够在很短的时间里判断一个数是否是质数.

如何将卡迈克尔数甄别出来,这里要用到 二次探测方法

算法流程:

  • p p p 是要判断的数, 2 2 2 特判后, p p p 如果是质数必须是奇数

  • p − 1 p-1 p1 分解为 2 r ∗ k 2^r*k 2rk,则有 a p − 1 = ( a k ) 2 r a^{p-1}=(a^k)^{2^r} ap1=(ak)2r

  • 可以先求出 a k a^k ak,然后将其不断平方,并取模 p p p

  • 对于任意的 0 < a < p 00<a<p,有 a k ≡ 1 ( m o d p ) a^k\equiv 1\pmod p ak1(modp),或者 a 2 s ∗ k ≡ − 1 ( m o d p ) , 0 ≤ s < r a^{2^s*k}\equiv-1\pmod p,0\le sa2sk1(modp),0s<r

    只要有一个等式成立,那么后面不断平方结果也是 1 1 1,在代码实现时就会立即跳出。

    如果一个都没有成立则说明一定不是个质数。

但是当 p p p 为合数的时候,也可能会骗过检测,这就是“伪素数”。

如果挑选多个不同的 a a a 来检测,那么就会降低骗过的概率。

这也就是 miller_rabin 要多次操作的原因。

容错率是 1 4 c \frac{1}{4}^c 41c,取决于操作次数 c c c

在竞赛中,用固定的几个数就够了,附表。

n ≤ n≤ n a a a
2047 2
1373653 2,3
9080191 31,73
25326001 2,3,5
4759123141 2,7,61
1122004669633 2,3,13,1662803
2152302898747 2,5,7,11
3474749660383 2,5,7,11,13
341550071728321 2,3,5,7,11,13,17
3825123056546413051 2,3,5,7,11,13,17,19

HDU2138

#include 
using namespace std;
#define int long long
int test[5] = { 2, 3, 61 };

int qkpow( int x, int y, int mod ) {
    int ans = 1;
    while( y ) {
        if( y & 1 ) ans = ans * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ans;
}

bool dfs( int n, int a, int d ) {
    if( n == a ) return 1;
    if( ! ( n & 1 ) ) return 0;
    while( ! ( d & 1 ) ) d >>= 1;
    int x = qkpow( a, d, n );
    while( d ^ ( n - 1 ) and x ^ 1 and x ^ ( n - 1 ) ) {
        x = x * x % n;
        d <<= 1;
    }
    return x == n - 1 or ( d & 1 );
}

bool isprime( int n ) {
    if( n == 2 ) return 1;
    for( int i = 0;i < 2;i ++ ) if( ! dfs( n, test[i], n - 1 ) ) return 0;
    return 1;
}

signed main() {
    int T, n;
    while( ~ scanf( "%lld", &T ) ) {
        int sum = 0;
        for( int i = 1;i <= T;i ++ ) {
            scanf( "%lld", &n );
            if( isprime( n ) ) sum ++;
        }
        printf( "%lld\n", sum );
    }
    return 0;
}

你可能感兴趣的:(#,随机化算法,算法,线性代数,几何学,素性测试,miller-rabin算法)