如何快速判断一个数是否为质数

203 阅读2分钟

1.试除法

检查2到√n之间的所有整数是否能整除n,时间复杂度O(✓n)

public static boolean isPrimeBasic(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;    // 2和3是质数
    if (n % 2 == 0 || n % 3 == 0) return false;
    
    // 检查6k±1形式的除数
    for (int i = 5; i * i <= n; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) {
            return false;
        }
    }
    return true;
}

2.米勒拉宾,基于费马小定理的改进概率测试

对于大数快速判断

  • 对于n < 2,047:k=1足够
  • 对于n < 1,373,653:k=3
  • 对于n < 9,080,191:k=31
  • 一般应用k=40可达到极高准确率

时间复杂度:O(k log³n)

public static boolean isPrimeMillerRabin(long n, int k) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0) return false;
    // 将n-1表示为d*2^s
    long d = n - 1;
    int s = 0;
    while (d % 2 == 0) {
        d /= 2;
        s++;
    }

    // 进行k轮测试
    Random rand = new Random();
    for (int i = 0; i < k; i++) {
        long a = 2 + rand.nextLong() % (n - 3);
        long x = modPow(a, d, n);
        if (x == 1 || x == n - 1) continue;
        
        boolean composite = true;
        for (int j = 0; j < s - 1; j++) {
            x = modPow(x, 2, n);
            if (x == n - 1) {
                composite = false;
                break;
            }
        }
        if (composite) return false;
    }
    return true;
    }
    private static long modPow(long a, long b, long mod) {
    long result = 1;
    a = a % mod;
    while (b > 0) {
        if (b % 2 == 1) {
            result = (result * a) % mod;
        }
        a = (a * a) % mod;
        b /= 2;
    }
    return result;
    }

```js

源码中判断数字是否为质数的函数

BigInteger.isProbablePrime() 方法

import java.math.BigInteger;

public class PrimeCheck {
    public static void main(String[] args) {
        BigInteger number = new BigInteger("123456789");
        
        // 使用 isProbablePrime 方法
        boolean isPrime = number.isProbablePrime(100); // 确定性参数
        
        System.out.println(number + " is prime? " + isPrime);
    }
}
public boolean isProbablePrime(int certainty) {
    if (certainty <= 0)
        return true;
    BigInteger w = this.abs();
    if (w.equals(TWO))
        return true;
    if (!w.testBit(0) || w.equals(ONE))
        return false;

    return w.primeToCertainty(certainty, null);//certainty是指调用者愿意容忍的不确定性的度量:如果调用返回 true 此 BigInteger 为素数的概率超过 (1 - 1/2certainty)。该方法的执行时间与该参数的值成正比。
}

boolean primeToCertainty(int certainty, Random random) {
    int rounds = 0;
    int n = (Math.min(certainty, Integer.MAX_VALUE-1)+1)/2;
    int sizeInBits = this.bitLength();
    if (sizeInBits < 100) { //小于100位使用passesMillerRabin,确定性测试
        rounds = 50;
        rounds = n < rounds ? n : rounds;
        return passesMillerRabin(rounds, random);
    }

    if (sizeInBits < 256) {
        rounds = 27;
    } else if (sizeInBits < 512) {
        rounds = 15;
    } else if (sizeInBits < 768) {
        rounds = 8;
    } else if (sizeInBits < 1024) {
        rounds = 4;
    } else {
        rounds = 2;
    }
    rounds = n < rounds ? n : rounds;
    //对于大整数,使用米勒-拉宾(Miller-Rabin)概率性测试和Lucas-Lehmer 测试等其他优化
    return passesMillerRabin(rounds, random) && passesLucasLehmer();
}

实现原理:

  • 对于小整数 (< 100位),使用确定性测试
  • 对于大整数,使用米勒-拉宾(Miller-Rabin)概率性测试
  • 结合了 Lucas-Lehmer 测试等其他优化

其他框架

  • Apache Commons Math: Primes 类
  • Google Guava: LongMath.isPrime()
  • JScience: 提供更多数论算法

对于大多数应用场景,BigInteger.isProbablePrime() 已经足够且方便使用,是 Java 中判断质数的标准方法。