找到第10001个素数

时间:2017-08-01 01:09:43

标签: java

我正在使用Project Euler#7编写代码:

public class Seven {

    public static void main(String[] args) {

        int i = 0;
        int c = 1;

        while (c <= 10001) {

            if (squareRootIsPrime(i)) {
                c++;
            }

            i++;

        }

        System.out.println(Math.sqrt(i));
    }

    public static boolean squareRootIsPrime (int n) {

        int x = 0;

        for (int d = 1; d <= n; d++) {
            if (n % d == 0) {x += 1;}
        }

        if (x == 3) {
            return true;
        } else {
            return false;
        }

    }

}

因为具有3个因子的数字的平方根是素数。 到目前为止,我的代码看起来是正确的,但是eclipse不会打印任何东西并终止程序,所以我的代码有什么问题?

3 个答案:

答案 0 :(得分:3)

第10001个素数的平方值不到110亿。 int可以容纳的最大值超过20亿。因此变量i会在到达第10001个素数的平方之前很久就会溢出。因为这种情况发生了,你永远不会看到第10001个素数。

理论上,如果您将变量i的类型和参数n更改为long,则可以使用此功能。但是,如果你这样做,你将留下代码,必须评估大约60个quintillion %操作(即,有19个零的6)。除非你有一台非常快的电脑,否则你的一生都不会完成。

您可能想要考虑可以使用的其他算法。

答案 1 :(得分:1)

10001的素数仅为104743。

您可以将代码更改为:

public class Seven {
public static void main(String[] args) {
    int i = 0;
    int c = 1;
    while (c <= 10001) {
    if (IsPrime(i)) {
            c++;
            System.out.println(i);
        }
        i++;
    }
    System.out.println(i);
}
public static boolean IsPrime(long x) {
    if (x<2) return false;
    if (x<=3) return true;
    for (long j = 2; j <= Math.sqrt(x) + 1; ++ j) 
    if (x % j == 0) return false;
    return true;
}

}

你判断数字的算法是素数很慢。你可以搜索如何判断一个数字是素数。快速时间成本是O(sqrt(N))。你应该注意到如果j导致x mod j == 0,循环将立即退出。所以这个算法比你想象的要快得多。

答案 2 :(得分:-1)

首先,您应该将i++;行移到if (squareRootIsPrime(i))上方 - 否则您将在实际搜索结果后打印该数字的平方根。

您没有打印结果的原因很简单,计算机计算时间太长。我现在正在测试c <= 500,但仍未达成结果。另外,正如Dawood已经提到的那样,int有一个我们无法超越的特定最大数量。

考虑到算法,你可以做很多调整 - 例如,每个素数都有一个你可以检查的正方形。增加潜在的素数而不是正方形会自动将不是整数的数字排除为素数候选者。

这是一个更快,更优化的算法版本。

public class Seven {

    public static void main(String[] args) {

        int i = 1;
        int c = 1;

        while (c <= 10001) {

            i++;

            if (isPrime(i)) {
                c++;
            }

        }

        System.out.println(i);
    }

    public static boolean isPrime(int i) {

        long n = (long)i*i;

        for (int d = 2; d < i; d++)
            if (n % d == 0) return false;
        return true;
    }
}

你必须首先设置i = 1,因为我之后会直接增加(素数从2开始)

d不必从1开始。数字总是可以分开。 这也意味着数量需要减少一个因素。但还有更多!

你可以在我而不是n之前停下来。这样做的原因是,对于每个大于i的数字,如果我们想得到结果n,我们需要一个小于i的对应因子来乘以该数字。如果我们从2向上增加到i,我们已经尝试了所有这些对应的数字,因此不需要检查任何大于i的数字。 另一个因素,因为这个数字将不再被自己分割。

你也不需要检查n / i,因为我是首先用作方法参数的数字,因此它总是正确的 - 而且,根是最后一个质数平方的三个因子

我们留下 0因素,现在可以安全地说明if (n % d == 0),参数是素数。