Understanding two’s complement

In this article, we dive into the topic of two’s complement number representation and try to explain how it works. We’ll work through it together, as I also need to check and validate my own understanding.

In a computer, numbers are represented in binary notation, as a sequence of bits. Since we need to work with negative numbers as well as positive ones, we need a system to represent the sign.

Two’s complement is a method to encode the sign information. Two’s complement is used by Java to represent integer numbers. For example, a Java language int is a 32-bit signed integer in the range of [-231, 231 – 1].

Why this range? We’ll get to that in a moment. But first, let’s look at numbers whose representation uses only the largest digit in a base.

In decimal, 9 is the largest digit. 9 = 10 – 1, 99 = 102 – 1, 999 = 103 – 1 and so forth.

In binary, 11 = 22 – 1, 1111 = 24 – 1.

In hexadecimal, F = 161 – 1 and FF = 162 – 1.

To conclude, in a base b, a number written by repeating the largest digit n times is equal to bn – 1.

To get the next largest number, we write 1 and turn all the other digits into zeros, effectively obtaining bn.

For example, FF16 + 1 = 10016 = 162

In two’s complement notation, the leftmost bit is reserved for the sign. By convention, it has a negative value.

Take the 32-bit number:

1_111111111111111111111111111111111111111

Can you guess what number it is?

The 31 bits to the right of the sign bit encode the number 231 – 1, as explained. The sign bit is equal to -231. Adding them up we obtain -1.

-231 + 231 – 1 = -1

We can verify this easily, using binary to hex conversion.

System.out.println(0xffffffff == -1); // true

If…

11111111111111111111111111111111

is -1, then…

10000000000000000000000000000000

is the minimum value of int, right?

System.out.println(0x80000000 == Integer.MIN_VALUE); // true

Also, zero followed by 31 set bits should be the maximum value of int.

System.out.println(0x7fffffff == Integer.MAX_VALUE); // true

Well, that explains why  [-231, 231-1] is the range of a 32-bit signed two’s complement integer.

Another thing we can do is to revert the sign, in order to find a number’s complement. To find the complement of a number x, we take 231x.

For ex., to find the representation of the number -15, we take 231 – 15.

10000000000000000000000000000000 -
00000000000000000000000000001111 =
11111111111111111111111111110001

Indeed, in Java, 0xfffffff1 maps to -15.