找出200万以下所有素数的总和

时间:2011-10-10 19:14:40

标签: java math primes

  

可能重复:
  How much time should it take to find the sum of all prime numbers less than 2 million?

我正在尝试使用简单的erathosthenes筛来解决项目euler上的这个问题:

  

低于10的素数之和为2 + 3 + 5 + 7 = 17.

     

找出200万以下所有素数的总和。

Link

我的代码仍然回答错误的答案 - 我一直得到142889228620项目euler不接受。

任何人都可以给我任何提示吗?这是代码:

import java.math.BigInteger;

public class Prime {
    /*
     * Input: an integer n > 1
     * 
     * Let A be an array of bool values, indexed by integers 2 to n, initially
     * all set to true.
     * 
     * for i = 2, 3, 4, ..., while i^2 ≤ n: if A[i] is true: for j = i^2, i^2 +
     * i, i^2 + 2i, ..., while j ≤ n: A[j] = false
     * 
     * Now all i such that A[i] is true are prime.
     */

        import java.math.BigInteger;

public class Prime {
    /*
     * Input: an integer n > 1
     * 
     * Let A be an array of bool values, indexed by integers 2 to n, initially
     * all set to true.
     * 
     * for i = 2, 3, 4, ..., while i^2 ≤ n: if A[i] is true: for j = i^2, i^2 +
     * i, i^2 + 2i, ..., while j ≤ n: A[j] = false
     * 
     * Now all i such that A[i] is true are prime.
     */

    public static void main(String[] args) {
        boolean[] array = new boolean[2000000];
        BigInteger counter = new BigInteger("0");
        for (int value = 0; value < array.length; value++) {
            array[value] = true;
        }
        for (int i = 2; i < array.length; i++) {
            if (array[i]) {
                int j = i * i;
                while (j > 0 && j < array.length) {
                    array[j] = false;
                    j += i;
                }
            }
        }
        for (int i = 2; i < array.length; i++) {
            if (array[i]) {
                counter = counter.add(BigInteger.valueOf(i));
            }
        }
        for (int value = 2; value < array.length; value++) {
            if(array[value]){
                System.out.println(value + ", ");
            }
        }
        System.out.println("\n" + counter);

    }

}

2 个答案:

答案 0 :(得分:7)

对于i

的大值,这会溢出
int j = i * i;

解决此问题的一种方法是使用long代替,因为这不会溢出这个大小的数字。然后,您也可以删除测试j > 0,因为j只有在出现溢出时才会变为负数。我猜你添加了那个测试,因为没有它就崩溃了,但错过了溢出可以到目前为止,你也可以得到错误的值,这会导致错误的数字被划掉筛,给你不正确的结果。

这会导致问题的一个例子是素数i = 92683。使用int算术,i * i溢出到203897,这也是一个素数,但会被错误划掉。

以下是使用long算法的简单修复:

for (long i = 2; i < array.length; i++) {
    if (array[(int)i]) {
        long j = i * i;
        while (j < array.length) {
            array[(int)j] = false;
            j += i;
        }
    }
}

我已经确认这会给出正确答案。

我们可以进一步改进,注意一旦i*i >= array.length,我们可以突破外部循环,因为内部循环永远不会运行。我们可以通过将外循环的条件更改为:

来实现
for(int i = 2; i * i < array.length; i++)

在这里,我们可以再次使用int,因为循环将在数字变得太大以至于它们将溢出之前结束。

答案 1 :(得分:2)

这段代码很糟糕:

        int j = i * i;
        while (j > 0 && j < array.length) {
            array[j] = false;
            j += i;
        }

你是从i * i开始并按i递增。你不应该减少吗?此外,如果i * i恰好大于200万,它甚至不会进入while循环。

编辑:这是一个修复:

        long j = 2 * i;
        while (j < array.length) {
            array[j] = false;
            j += i;
        }