The negative numbers also need a slot. Computers just have ones and zeroes; there is no 'minus sign'. So we 'encode' negative numbers with zeroes and ones. The first bit is the sign bit; if it is a 1, the number is actually negative. Hence why the largest (non-negative!) number is 0111 1111 1111 1111 1111 1111 1111 1111. In decimal it is, as you would expect, 2^0+2^1+2^2+.....2^30. Which is the same as 2^31-1, which is 2147483647. And indeed it is:
System.out.println(Integer.MAX_VALUE); // prints 2147483647.
System.out.println(0b0111_1111_1111_1111_1111_1111_1111_1111); // same
int v = 0;
for (int i = 0; i < 31; i++) {
int z = (int) Math.pow(2, i);
v += z;
}
System.out.println(v); // same
The '0' also has to go somewhere, and it is all zero bits. That means a bit of an intriguing detail: There are, of course, as many numbers that starts with a 1-bit as with a 0-bit, but the 0-bit space (our positive numbers) needs to allocate one sequence for zero, but the negative space does not. Hence, the largest negative number you can represent is actually one higher: It's -2^31:
System.out.println(Integer.MIN_VALUE);
This prints -2147483648.
Negative numbers are represented in 2's complement. Basically, 'in reverse'. 1000 0000 0000 0000 0000 0000 0000 0000
is in fact -2147483648, and 1111 1111 1111 1111 1111 1111 1111 1111
is -1. You can read e.g. wikipedia about all the details of two's complement, but one massive advantage is that the +
and -
operations (as well as increment/decrement-by-one operations) work identically regardless of whether you treat the bits as unsigned (negative numbers are not possible, can represent 0 up to 2^32-1), or as signed (negative numbers ARE possible, can represent -2^31 to +2^31-1). Now 'is it signed or unsigned' is math-wise irrelevant, and that saves instructions.
For a quick moment of enlightenment: Take -1 in two's complement (in bits: 32x 1
), and add 1 to it. This trivially results in a 1 followed by thirty-two zeroes, and as computers just lop off the excess, that's just thirty-two zero bits. Which represents zero. And -1 incremented by 1 is.. indeed zero. Neat!
2's complement boils down to 'flip all bits and add one to it', e.g:
5 = 0000.....0101
- -5 thus becomes: 1111....1011.
- reversing that operation produces 000...0101 again.