可能重复:
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万以下所有素数的总和。
我的代码仍然回答错误的答案 - 我一直得到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);
}
}
答案 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;
}