质数计算器不适用于大数

Prime Number Calculator Not Working With Large Numbers

我正在尝试打印出一个数的所有质因数。我的代码如下:

public static boolean isPrime(long n){

    long i = n;

    while (i > 0){

        if (n % i == 0 && !(i == 1 || i == n)){

            return false;

        }
        i--;
    }

    return true;

}


public static void primeFactors(long n){

    long i = n;
    while (i > 0){

        if (isPrime(i)){
            System.out.println(i);
        }
        i--;
    }

}

此代码适用于较小的数字:5、5000,例如当我向该方法输入 600851475143 时,我的程序运行并且没有任何输出。为什么会这样?

当给定输入数字 600851475143 时,您的程序没有打印任何内容,因为您检查质数的方式很慢。只要有足够的耐心,您的程序就会打印一些东西——但这可能需要数小时、数天甚至数年。您需要为此计算提出更好的算法。

你的素性测试函数太糟糕了。

  1. 快速取胜:向前数而不是向后数。目前,您至少会数到一半的数字,直到找到一个因数!这可能是您观察到的延迟的原因。

  2. 更好一点:计算奇数直到平方根。

  3. 也许更好:计算素数直到平方根。根据要求使用筛子预先计算。

简短回答:程序实际上并没有终止。您使用的方法是检查素数的最低效方法之一。查看 Sieve of Eratosthenes 以获得易于理解且相当高效的算法。

不需要检查n个数来检查n是不是素数,从0开始就够了n/2:

public static boolean isPrime(long n){

        long i = 2;

        while (i < n/2){

            if (n % i == 0 ){

                return false;

            }
            i++;
        }

        return true;

    }

这将使性能翻倍

虽然数字没有超出长原始值范围 (9,223,372,036,854,775,807),但您应该使用 BigInteger,因为 BigInteger 具有用于此目的的功能,而且我认为它比包括您在内的其他实现更有效。

new BigInteger(yourNumer).isProbablePrime(100) // returns true or false

此外,素数测试是通过使用许多数学方法和算法完成的,有一些方法对于 < 64 位的数字运行速度更快,还有一些方法可以更好地测试更大的数字。还有其他一些方法here

将您的方法更改为以下内容:

public static boolean isPrime(long num) {
    for (int i = 2; i < Math.sqrt(num); i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}

应该够高效了。

其他答案都集中在您的功能 isPrime 上,该功能效率低下。我将转而关注您的函数 primeFactors,这是不正确的。实际上,您可以看到它以相反的顺序打印了直到 n 的素数,而不是 n 的素因数。相反,做

public static void primeFactors(long n) {
  // Handle factors of 2
  while (n%2==0) {
    System.out.println(2);
    n /= 2;
  }

  // Handle all odd prime factors except the largest
  for (long p = 3; p*p <= n; p += 2) {
    while (n%p == 0) {
      System.out.println(p);
      n /= p;
    }
  }

  // Handle the largest prime factor
  if (n > 1) {
    System.out.println(2);
  }
}

您可能会注意到从未使用过 isPrime!其实不需要:只要你找到它们就把它们去掉,你打印的所有数字都是质数。

这里有很多可能的改进,但这种方法目前已经足够快了。一种简单的方法是计算 Math.sqrt(n) 的上限并将 p 与其进行比较,而不是每次都将 p 乘以自身。您可能还想检查 0 和负数,可能还有 1,具体取决于您要如何处理这些数字。