找到更大的素数时遇到错误

时间:2017-02-08 15:31:57

标签: java primes sieve

我做了一个简单的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);;
    }

我的目标根本不是找到答案,但很多时候由于这些类型的错误我放弃了我的代码。我想找到他们的来源。

3 个答案:

答案 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。

因此,尝试对变量itargetcycles使用long或BigInteger而不是int。即便如此,你仍然需要重新考虑你的逻辑,因为问题不是溢出本身,而是数组不够长。