我做了一个简单的erastothenes程序筛,计算项目euler的素数之和。它适用于100,1,000,10000等等,但当我做1或2百万时,它给了我这个:
java.lang.ArrayIndexOutOfBoundsException: -2146737495
对于较小的数字不会发生,我使用布尔数组。
boolean[] primes = new boolean[2000001];
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 2; i < primes.length; i++){
primes[i] = true;
}
boolean stop = false;
int target = 2;
int cycles = 1;
while (!stop) {
list.add(target);
for (int i = target;; i ++) //
{
if (target*i >= primes.length ) {//
break;
}
primes[target*i] = false;//
}
for (int i = target + 1; ; i ++) {
if(i >= primes.length) {
stop = true;
break;
}
else if (primes[i]) {
target = i;
break;
}
}
cycles ++;
}
int sum = 0;
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);;
}
我的目标根本不是找到答案,但很多时候由于这些类型的错误我放弃了我的代码。我想找到他们的来源。
答案 0 :(得分:2)
您的检查错误,不会考虑整数溢出。
for (int i = target;; i ++) //
{
if (target*i >= primes.length ) {// This is the check
break;
}
primes[target*i] = false;// Here is where it overflows
}
一旦你点击i
使target * i
大于一个整数就可以容纳,整数就会溢出。这意味着现在它将变为负面。当然,对于负数,target*i >= primes.length
将是错误的。
当然,负数不能是数组中的索引。它应该在休息时停止,但它没有因为条件没有得到满足。
您应该做的是计算允许的最大i
,并将其作为循环条件:
int maxI = primes.length / target;
for (int i = target; i < maxI; i ++) //
{
primes[target*i] = false;// Here is where it overflows
}
maxI
是您可以乘以target
但仍未达到primes.length
的最大数量。现在你不再需要你的支票了(因为target
乘以i
永远不会产生大于primes.length
的数字。而且它也永远不会溢出,因为乘法总是产生一个数字这小于数组的大小,因此小于Integer.MAX_VALUE
。
另一种更便宜(减少乘法)的方法是:
if ( primes.length / target >= target ) {
for (int i = target * target; i < primes.length; i += target ) //
{
primes[i] = false;
}
}
如果您有一个巨大的if
,则需要检查target
以避免溢出。
答案 1 :(得分:0)
那是因为您使用的是int,其上限为2 ^ 31-1:请参阅https://en.wikibooks.org/wiki/Java_Programming/Primitive_Types
要处理大数字,您应该使用BigInteger类。
答案 2 :(得分:0)
您的primes
数组存在问题。
首先,通过读取错误,您的数组对于您的逻辑显然不够“长”,因为您将其定义为boolean[] primes = new boolean[2000001];
并且您的ArrayIndexOutOfBoundsException为-2146737495。
因此,尝试对变量i
,target
和cycles
使用long或BigInteger而不是int。即便如此,你仍然需要重新考虑你的逻辑,因为问题不是溢出本身,而是数组不够长。