-Integer.MIN_VALUE == Integer.MIN_VALUE but -Byte.MIN_VALUE != Byte.MIN_VALUE

Somewhat surprisingly, these two expressions evaluate to true:

-Integer.MIN_VALUE == Integer.MIN_VALUE -Long.MIN_VALUE == Long.MIN_VALUE

Bytes and shorts however seem to behave as expected:

-Byte.MIN_VALUE == Byte.MIN_VALUE -Short.MIN_VALUE == Short.MIN_VALUE

What’s going on here?

Explanation

Java uses two’s complement to represent integer values. In this representation the values are not symmetrical around origo. There's one more negative value than there are positive values. The smallest value has no positive counterpart! For example:

Integer.MIN_VALUE equals −2 31

equals −2 Integer.MAX_VALUE equals +231−1

When you try to negate −231 you get 231, which is larger than the the maximum int value, so it overflows and rolls over to the negative side.

Here’s an illustration:

MIN_VALUE 0 MAX_VALUE Overflow! roll over

In other words, Integer.MIN_VALUE is its own negation. This causes other surprises too, such as Math.abs(Integer.MIN_VALUE) , which is implemented as x < 0 ? -x : x , to return a negative value.

What’s up with byte and short ?

Byte and short values are also stored in two’s complement. Java however, does not do arithmetic directly on bytes and shorts. Instead, they are promoted to int s, and then the unary minus is computed.

If b is a byte, then -b is equivalent to -((int) b) .

One way to illustrate this is to create two overloaded methods…

void m ( byte b ) { System . out . println ( "A byte" ); } void m ( int i ) { System . out . println ( "An int" ); }

…and call them as follows:

byte b = 0 ; m(b); m(-b);

So -Byte.MIN_VALUE equals 128, but in the form of an int . If we cast this result back to a byte (for which the maximum value is 127) it rolls over and becomes −128, just as in the case of ints and longs:

( byte ) -Byte.MIN_VALUE == Byte.MIN_VALUE ( short ) -Short.MIN_VALUE == Short.MIN_VALUE

Here’s an illustration:

ints 0 −128 128 bytes 0 cast promote −128 128 Overflow roll over