This code:
System.out.println(Math.abs(Integer.MIN_VALUE));
Returns -2147483648
Should it not return the absolute value as 2147483648
?
The Integer. MIN_VALUE is a constant in the Integer class that represents the minimum or least integer value that can be represented in 32 bits, which is -2147483648, -231. This is the lowest value that any integer variable in Java can hold.
abs(int a) returns the absolute value of an int value. If the argument is not negative, the argument is returned. If the argument is negative, the negation of the argument is returned.
Integer. MAX_VALUE represents the maximum positive integer value that can be represented in 32 bits (i.e., 2147483647 ).
Abs() Method | Set – 2. In C#, Abs() is a Math class method which is used to return the absolute value of a specified number. This method can be overload by passing the different type of parameters to it. There are total 7 methods in its overload list.
Integer.MIN_VALUE
is -2147483648
, but the highest value a 32 bit integer can contain is +2147483647
. Attempting to represent +2147483648
in a 32 bit int will effectively "roll over" to -2147483648
. This is because, when using signed integers, the two's complement binary representations of +2147483648
and -2147483648
are identical. This is not a problem, however, as +2147483648
is considered out of range.
For a little more reading on this matter, you might want to check out the Wikipedia article on Two's complement.
The behaviour you point out is indeed, counter-intuitive. However, this behaviour is the one specified by the javadoc for Math.abs(int)
:
If the argument is not negative, the argument is returned. If the argument is negative, the negation of the argument is returned.
That is, Math.abs(int)
should behave like the following Java code:
public static int abs(int x){ if (x >= 0) { return x; } return -x; }
That is, in the negative case, -x
.
According to the JLS section 15.15.4, the -x
is equal to (~x)+1
, where ~
is the bitwise complement operator.
To check whether this sounds right, let's take -1 as example.
The integer value -1
is can be noted as 0xFFFFFFFF
in hexadecimal in Java (check this out with a println
or any other method). Taking -(-1)
thus gives:
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
So, it works.
Let us try now with Integer.MIN_VALUE
. Knowing that the lowest integer can be represented by 0x80000000
, that is, the first bit set to 1 and the 31 remaining bits set to 0, we have:
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
And this is why Math.abs(Integer.MIN_VALUE)
returns Integer.MIN_VALUE
. Also note that 0x7FFFFFFF
is Integer.MAX_VALUE
.
That said, how can we avoid problems due to this counter-intuitive return value in the future?
We could, as pointed out by @Bombe, cast our int
s to long
before. We, however, must either
int
s, which does not work because Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
s somehow hoping that we'll never call Math.abs(long)
with a value equal to Long.MIN_VALUE
, since we also have Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
.We can use BigInteger
s everywhere, because BigInteger.abs()
does indeed always return a positive value. This is a good alternative, though a bit slower than manipulating raw integer types.
We can write our own wrapper for Math.abs(int)
, like this:
/** * Fail-fast wrapper for {@link Math#abs(int)} * @param x * @return the absolute value of x * @throws ArithmeticException when a negative value would have been returned by {@link Math#abs(int)} */ public static int abs(int x) throws ArithmeticException { if (x == Integer.MIN_VALUE) { // fail instead of returning Integer.MAX_VALUE // to prevent the occurrence of incorrect results in later computations throw new ArithmeticException("Math.abs(Integer.MIN_VALUE)"); } return Math.abs(x); }
int positive = value & Integer.MAX_VALUE
(essentially overflowing from Integer.MAX_VALUE
to 0
instead of Integer.MIN_VALUE
)As a final note, this problem seems to be known for some time. See for example this entry about the corresponding findbugs rule.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With