开发者

Find the sum of all the primes below two million [duplicate]

开发者 https://www.devze.com 2023-04-12 14:37 出处:网络
This question already has answers here: Closed 10 years ago. Possible Duplicate: How much time should it take to find the sum of all prime numbers less than 2 million?
This question already has answers here: Closed 10 years ago.

Possible Duplicate:

How much time should it take to find the sum of all prime numbers less than 2 million?

I am trying to implement a simple sieve of erathosthenes to solve this question on project euler :

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.

Link

My code keeps returning the wrong answer though - I keep getting 142889228620 which project euler isn't accepting.

Can anyone give me any hints as to why? Here is the code:

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 = 开发者_如何学Ccounter.add(BigInteger.valueOf(i));
            }
        }
        for (int value = 2; value < array.length; value++) {
            if(array[value]){
                System.out.println(value + ", ");
            }
        }
        System.out.println("\n" + counter);

    }

}


This will overflow for large values of i:

int j = i * i;

One way of solving this is using long instead, as that will not overflow with numbers of this size. You can then also remove the test j > 0, as j can only go negative if you get overflows. I'm guessing you added that test because it crashed without it, but missed that the overflow can go so far that you can also get bad positive values, which causes the wrong numbers to be crossed out in your sieve, giving you incorrect results.

One example of how this causes trouble is the prime i = 92683. Using int arithmetic, i * i overflows to 203897, which is also a prime, but will be incorrectly crossed out.

Here is a simple fix using long arithmetic:

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've verified that this gives the correct answer.

We can improve further on this by noting that once i*i >= array.length, we can break out of the outer loop, as the inner loop will never run. We can do this by changing the condition of the outer loop to:

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

Here, we can use int again, as the loop will end before the numbers get so large that they will overflow.


This code is bad:

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

You're starting at i*i and incrementing by i. Shouldn't you be decrementing? Futhermore, if i*i happens to be greater than 2 million, it won't even enter the while loop.

EDIT: here's a fix:

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号