Java Reference
In-Depth Information
Exception in thread "main" ArrayIndexOutOfBoundsException: -2
at Mod.main(Mod.java:9)
What is going on here?
The problem lies in the program's use of the Math.abs method, which results in erroneous mod 3
values. Consider what happens when i is -2. The program computes the value Math.abs(-2) % 3 ,
which is 2 , but the mod 3 value of -2 is 1. This would explain incorrect numerical results, but it
leaves us in the dark as to why the program throws an ArrayIndexOutOfBoundsException . This
exception indicates that the program is using a negative array index, but surely that is impossible:
The array index is calculated by taking the absolute value of i and computing the remainder when
this value is divided by 2. Computing the remainder when a nonnegative int is divided by a
positive int is guaranteed to produce a nonnegative result [JLS 15.17.3]. Again we ask, What is
going on here?
To answer that question, we must go to the documentation for Math.abs . This method is named a
bit deceptively. It nearly always returns the absolute value of its argument, but in one case, it does
not. The documentation says, "If the argument is equal to the value of Integer.MIN_VALUE , the
result is that same value, which is negative." Armed with this knowledge, it is obvious why the
program throws an immediate ArrayIndexOutOfBoundsException . The initial value of the loop
index i is Integer.MIN_VALUE , which generates an array index of Math.abs(Integer.MIN_VALUE)
% 3 , which equals Integer.MIN_VALUE % 3 , or 2 .
To fix the program, we must replace the bogus mod calculation ( Math.abs(i) % MODULUS ) with
one that actually works. If we replace this expression with an invocation of the following method,
the program produces the expected output of 1431655765 1431655766 1431655765 :
private static int mod(int i, int modulus) {
int result = i % modulus;
return result < 0 ? result + modulus : result;
}
The lesson of this puzzle is that Math.abs is not guaranteed to return a nonnegative result. If its
argument is Integer.MIN_VALUE — or Long.MIN_VALUE for the long version of the method— it
returns its argument. The method is not doing this just to be ornery; this behavior stems from the
asymmetry of two's-complement arithmetic, which is discussed in more detail in Puzzle 33 . Briefly,
there is no int value that represents the negation of Integer.MIN_VALUE and no long value that
represents the negation of Long.MIN_VALUE . For library designers, it might have been preferable if
Math.abs threw IllegalArgumentException when it was passed Integer.MIN_VALUE or
 
 
Search WWH ::




Custom Search