Miller-Rabin素性测试算法

M i l l e r − r a b i n Miller-rabin Millerrabin算法是一个用来快速判断一个正整数是否为素数的算法,它利用了费马小定理和二次探测:

  • 费马小定理:如果 p p p是质数且 a ⊥ p a \perp p ap互质,那么 a p − 1 ≡ 1    ( m o d    p ) a^{p-1} \equiv 1 ~~ (mod~~ p) ap11  (mod  p)恒等于 1 1 1

    也就是对于所有小于 p p p的正整数 a a a来说都应该符合 a p − 1    ( m o d    p ) a^{p-1}~~(mod~~p) ap1  (mod  p)恒等于 1 1 1。那么根据逆否命题,对于一个 p p p,我们只要举出一个 a ( a < p ) a(aa(a<p)不符合这个恒等式,则可判定 p p p不是素数。 M i l l e r − r a b i n Miller-rabin Millerrabin算法就是多次用不同的 a a a来尝试 p p p是否为素数

  • 二次探测定理:如果 p p p是一个素数,那么对于正整数 x ( x < p ) x(xx(x<p),若 x 2 ≡ 1    ( m o d    p ) x^2 \equiv 1 ~~(mod~~p) x21  (mod  p) ,则 x = 1    o r    x = p − 1 x=1~~or~~x=p-1 x=1  or  x=p1。逆否命题:如果对于正整数 x ( x < p ) x(xx(x<p),若 x 2 ≡ k    ( m o d    p ) , k ≠ 1 x^2 \equiv k ~~(mod~~p),k \neq 1 x2k  (mod  p),k=1,则 p p p不是素数(二次探测定理的正确性可以通过求解二次同余方程验证)

    根据这个定理,我们要计算 a p − 1    m o d    p a^{p-1}~~ mod~~ p ap1  mod  p是否等于 1 1 1时,可以这样计算,设 p − 1 = k ∗ 2 t p-1=k*2^t p1=k2t,从 a k a^k ak开始,不断将其平方直到得到 a p − 1 a^{p-1} ap1,一旦发现某次平方并对 p p p取模后等于 1 1 1,那么说明符合了二次探测定理的逆否命题使用条件,立即检查 x x x是否等于 1 1 1 p − 1 p-1 p1,如果都不是则可直接判定 p p p为合数

inline ll mul(ll a, ll b, ll p) {
        //wa了尝试慢速乘或者改为__int128
    if (p <= 1000000000) return a * b % p;
    else if (p <= 1000000000000LL) return (((a * (b >> 20) % p) << 20) + (a * (b & ((1 << 20) - 1)))) % p;
    else {
     
        ll d = (ll) floor(a * (long double) b / p + 0.5);
        ll ret = (a * b - d * p) % p;
        if (ret < 0) ret += p;
        return ret;
    }
}

//inline ll mul(ll x, ll n, ll p) {
     
//    ll ans = 0;
//    x %= p;
//    while (n) {
     
//        if (n & 1) ans = (ans + x) % p;
//        x = (x + x) % p;
//        n >>= 1;
//    }
//    return ans;
//}

inline ll qkp(ll x, ll n, ll p) {
     
    ll ans = 1;
    x %= p;
    while (n) {
     
        if (n & 1) ans = mul(ans, x, p);
        x = mul(x, x, p);
        n >>= 1;
    }
    return ans;
}

bool miller_rabin(ll n, int t = 20) {
     
    if (n == 2) return true;
    if (n < 2 || !(n & 1)) return false;
    ll m = n - 1;
    int k = 0;
    while ((m & 1) == 0) {
     
        m >>= 1;
        k++;
    }
    for (int i = 0; i < t; i++) {
     
        ll a = rand() % (n - 1) + 1;
        ll x = qkp(a, m, n), y = 0;
        for (int j = 0; j < k; j++) {
     
            y = mul(x, x, n);
            if (y == 1 && x != 1 && x != n - 1) return false;
            x = y;
        }
        if (y != 1) return false;
    }
    return true;
}

Java大数判断素数

J a v a Java Java B i g I n t e g e r BigInteger BigInteger类封装了大数的米勒罗宾判素数的方法:

import java.math.BigInteger;
import java.util.*;

public class Main{
     
    public static void main(String[] args){
     
        BigInteger x;
        Scanner in = new Scanner(System.in);
		x = in.nextBigInteger();
		if(x.isProbablePrime(50))  	//相当于该数是素数的概率超过99%
			System.out.println("Yes");
		else
			System.out.println("No");
    }
}

你可能感兴趣的:(数论)