【模板】Miller_Rabin 素数测试

如同标题所述,Miller_Rabin 是用来测试一个数是否为素数的算法。然而,Miller_Rabin是有缺陷的,这就是它单次执行所得的结果并不完全正确,不过我们可以将这个算法多执行几次来让它的正确率趋近于 100% 100 %

Tools T o o l s

  • Fetmat F e t m a t 小定理:若 p p 为素数, a a 为正整数,且 (a,p)=1 ( a , p ) = 1 ,则 ap11(modp) a p − 1 ≡ 1 ( mod p ) .

    Fetmat F e t m a t 小定理的逆命题不是真命题,但是满足两个条件的 p p 有很大概率是素数,所以多测试几次可以提高判断准确程度。

  • 二次探测定理:如果 p p 是一个素数, 0<x<p 0 < x < p , 则方程 x21(modp) x 2 ≡ 1 ( mod p ) 的解为 x=1 x = 1 x=p1 x = p − 1 .

    同样也是逆用这个定理,若 x21(modp) x 2 ≡ 1 ( mod p ) x1 x ≠ 1 xp1 x ≠ p − 1 ,则 p p 一定不是质数,与 Fetmat F e t m a t 小定理结合提高准确度。

  • 快速幂。

Algorithm A l g o r i t h m

  • 给定一个整数 N N ,即要求判断的数.
  • 计算奇数 M M 使得 N=2rM+1 N = 2 r ∗ M + 1 .
  • 选择随机数 A<N A < N (也可以是自己指定)
  • 对于 i<r ∃ i < r , 若 A2iMmodN=N1 A 2 i ∗ M mod N = N − 1 ,则 N N 通过测试。
  • 或者,若 AMmodN=1 A M mod N = 1 ,则 N N 通过测试。
  • 多次选取 A A ,若 N N 全部通过,则判定 N N 是素数。

由于Miller_Rabin是概率算法,所以要多次选取素数保证正确程度, int i n t 范围内 使用 2,3,61 2 , 3 , 61 这三个数即可。实在担心的话取 2,3,7,19,61,24251 2 , 3 , 7 , 19 , 61 , 24251 ,准确性就相当高了。

Code1 C o d e 1

\\随机
LL FastPower(LL a, LL p, LL k) {
    LL ans = 1;
    while (p) {
        if (p & 1) ans = (ans * a) % k;
        a = (a * a) % k;
        p >>= 1;
    }
    return ans;
}
bool judge(LL a, LL n, LL m, LL r) {
    LL x = FastPower(a, m, n);
    if (x == 1 || x == n - 1) return true;
    while (r--) {
        x = (x * x) % n;
        if (x == n - 1) return true;
    }
    return false;
}
bool Miller_Rabin(LL n) {
    if (n == 2) return true;
    if (n == 1 || !(n & 1)) return false;
    LL m = n - 1, r = 0;
    while (!(m & 1)) {
        r++;
        m >>= 1;
    }
    for (int i = 0; i < 10; i++) {
        int a = rand() % (n - 1) + 1;
        if (!judge(a, n, m, r))
            return false;
    }
    return true;
}

Code2 C o d e 2

\\指定
const int len = 6;
const LL base[len] = {2, 3, 7, 19, 61, 24251};
LL FastPower(LL a, LL p, LL k) {
    LL ans = 1;
    while (p) {
        if (p & 1) ans = (ans * a) % k;
        a = (a * a) % k;
        p >>= 1;
    }
    return ans;
}
bool judge(LL a, LL n, LL m, LL r) {
    LL x = FastPower(a, m, n);
    if (x == 1 || x == n - 1) return true;
    while (r--) {
        x = (x * x) % n;
        if (x == n - 1) return true;
    }
    return false;
}
bool Miller_Rabin(LL n) {
    if (n == 1) return false;
    for (int i = 0; i < len; i++) 
        if (n == base[i])
            return true;
    for (int i = 0; i < len; i++)
        if (n % base[i] == 0)
            return false;
    LL m = n - 1, r = 0;
    while (!(m & 1)) {
        r++;
        m >>= 1;
    }
    for (int i = 0; i < len; i++) {
        if (!judge(base[i], n, m, r))
            return false;
    }
    return true;
}

你可能感兴趣的:(素数判定,Miller_Rabin)