【模板】Miller_Rabin 素数测试

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

T o o l s

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

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

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

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

  • 快速幂。

A l g o r i t h m

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

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

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;
}

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;
}

猜你喜欢

转载自blog.csdn.net/Diogenes_/article/details/81019967