0

I have the following method:

public static boolean[] mk2(int n) {
    boolean[] isPrime = new boolean[n + 2];
    isPrime[1] = false;
    isPrime[2] = true;
    for (int i = 3; i <= n; i++) {
        if((i & 1) == 0) {
           isPrime[i] = false;
        } else {
           isPrime[i] = true;
        }
    }
    // cycle through to see if a number has factors other than 1 & itself
    for(int y = 3; y <= n; y++) {
        System.out.print("Test y " + y);
        if(isPrime[y]) {
            for(int i = 2; i <= y-1; i++) {
                if(y%i==0){
                    // stop here if it isn't prime
                    isPrime[y] = false;
                    System.out.println(" disproved");
                    i = y + 1;
                }     
            }
            if(isPrime[y]){
                    System.out.println(" is prime and disproves:");
                    for (int j = y; y*j <= n; j++) {
                        if(y*j<=n) {
                            isPrime[y*j] = false;
                            System.out.print(" "+(y*j)+" ");
                        }
                    }
                    System.out.println(".");
                }
        } else {
            System.out.println(" already disproved");
        }
    }
    System.out.println("Primes");
    int x = 0;
    for(int i=1; i <= n; i++) {
        if(isPrime[i]) {
            System.out.print(i+", ");
            x++;
        }
        if(x >= 61) {
            System.out.println(";");
            x = 0;
        }
    }
    System.out.println(".");

    return isPrime;
}

which generally works fine but when I set n to 100000 I get the following exception java.lang.ArrayIndexOutOfBoundsException: -2146737495

from what I have been able to find java.lang.ArrayIndexOutOfBoundsException normally occurs when you try to access a point in the array greater than its defined size e.g.

int[] x = new int[5];
x[10] = 2;

so I am a bit confused as to what is happening here. Any Ideas?

bakoyaro
  • 2,550
  • 3
  • 36
  • 63
Zander Brown
  • 637
  • 8
  • 16
  • 3
    Have you tried stepping through it with a debugger to see when it over-subscripts the array? – Frecklefoot Nov 03 '15 at 15:58
  • 1
    an index should be positive :) – nano_nano Nov 03 '15 at 15:59
  • Your logic is a bit hard to follow, but I don't see where you're using the first element, e.g. isPrime[0]. And in one loop you have the control statement as a `<=` which will generally over-subscript your array. You usually want just `<`. – Frecklefoot Nov 03 '15 at 16:02
  • the last thing show in the terminal Is `Test y 46347 already disproved` `Test y 46348 already disproved` `Test y 46349 is prime and disproves:` ` Exception occurred.` so I'm assuming it goes wrong around their but as the array is set to n + 2 and I check whether y*j is greater than n so i'm not sure how its happening – Zander Brown Nov 03 '15 at 16:02
  • 1
    Two words: **prior research** (really really easy to resolve without asking a new question); and **overflow**. OK, so that's more than two words; but still the essence of what matters in the context of your question. – GhostCat Nov 03 '15 at 16:03
  • @Stefan Beike i don't see where it went negative – Zander Brown Nov 03 '15 at 16:03
  • the exception told you it is negative. the answer from @Mena is a good approach. – nano_nano Nov 03 '15 at 16:05
  • This question seems related: http://stackoverflow.com/questions/11202276/getting-arrayindexoutofboundsexception-after-a-certain-input-value – William Greendale Nov 03 '15 at 16:12
  • Just an FYI, Java Arrays are 0 based, meaning the first element of your array will be in isPrime[0] – bakoyaro Nov 03 '15 at 16:13
  • The if statement checking that `y*j <= n` inside your for loop, which checks that `y*j <= n` is pointless. You should actually be checking that `y*j <= n && y*j > 0`. This will avoid your error. You don't need to and shouldn't change anything to `long` unless `n` itself is `long`. – Monkeygrinder Nov 03 '15 at 16:30

4 Answers4

2

The error very likely comes from an arithmetic overflow of int.

The most likely root cause is your reference to element isPrime[y*j], where y * j overflows the int and returns Integer.MIN_VALUE + (the amount overflown - 1).

You should set a breakpoint and debug those values.

Mena
  • 47,782
  • 11
  • 87
  • 106
  • Didn't think of that. how would i set it long? – Zander Brown Nov 03 '15 at 16:06
  • @AlexanderBrown you can use `long` in `for` loops. Beware though, it's likely that you don't want to use arrays with such large numbers of elements (see `OutOfMemoryError`s) and there might be a genuine bug in the code. Debug first is my advice. – Mena Nov 03 '15 at 16:08
  • I have found its trying to do `46349*46349` which is greater than `Integer.MAX_VALUE` but is also bigger than n which shouldn't be happening – Zander Brown Nov 03 '15 at 17:01
  • @AlexanderBrown yeah i suspected it would be a functional bug :) – Mena Nov 03 '15 at 17:01
  • found the problem! I setting `j = y` instead of `j = 2` making my results dodgy and causing the calculation to exceed `Integer.MAX_VALUE` – Zander Brown Nov 03 '15 at 17:07
  • @AlexanderBrown nice :) – Mena Nov 03 '15 at 17:08
1

The problematic statement is isPrime[y*j] = false; which is generating a number outside of Integer range. Once it reach maximum number and start from negitive numbers, and you get the exception because the index should be >= 0 and < len

More specifically you are trying to multiply y= 46349, j=46349 which results in 2148229801 which is greater then Integer.MAX_VALUE=2147483647

ata
  • 8,853
  • 8
  • 42
  • 68
0

When integer overflows, it goes back to the minimum value and continues from there. If it underflows, it goes back to the maximum value and continues from there.

So According to

java.lang.ArrayIndexOutOfBoundsException: -2146737495

Because index must be positive :

According java language specification :

All array accesses are checked at run time; an attempt to use an index that is less than zero or greater than or equal to the length of the array causes an ArrayIndexOutOfBoundsException to be thrown.

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.13

Keval
  • 1,857
  • 16
  • 26
0

The int is 32-bit and long is 64-bit. So it provides a bigger range. What you should do is convert variables j and y to longs:

for(long y = 3; y <= n; y++) {

for (long j = y; y*j <= n; j++) {

And wherever you index an array, you need to convert it to an

if(isPrime[(int)y]) {

What's happening is that you're multiplying two ints which exceed the int range and it thus becomes negative and the condition below satisfies as true:

if(y*j<=n) {

and then it is trying to assign to some negative index in your array:

    isPrime[y*j] = false;
ergonaut
  • 6,929
  • 1
  • 17
  • 47