In my last article, we talked about representing signed numbers in binary. One of the most commonly used methods in computer systems is Two's Complement. To remind ourselves, here's how we store the number -6
as a Two's Complement using four bits:
Write down the number
6
in binary form:0110
.Flip all the bits (turning it into One's Complement):
1001
.Add one:
1010
.
So the number -6
represented as Two's Complement is 1010
. When I first encountered Two's Complement, what confused me the most was the last step. Why do we have to add 1
?🤔
This question bugged me, so I did some research. In this article, I'd like to share what I found. Just a quick disclaimer: I did this solely out of curiosity. I have no formal evidence that my conclusions are correct, but I did my best to explain my thinking. If you encounter an error or any ambiguity, please let me know, and I'll do my best to correct it.
Clocks and modular arithmetic
Before we try to answer the mysterious step of adding one, let's take a second and check what time it is. In my case, it's 11 AM. If the clock shows 11:00, what will it show in 3 hours? Obviously, 2:00.
This is obvious because we are so used to clocks and measuring time, but let's think about it. We add 3 to 11 and get 2. Because we are using a 12-hour clock, the largest number it shows is 12. When we exceed 12, we "cycle" back to 1, then 2, 3, and so on.
This leads us to modular arithmetic - a system where numbers "wrap around" upon reaching a given fixed quantity, which we call the modulus. In modular arithmetic, we care about the remainder after dividing a number by the modulus.
In our example, if it's 11:00, in 3 hours the clock will show 2:00 because the remainder after dividing \(11+3=14\) by 12 (our modulus) is 2. We can write that as:
$$14\equiv 2\ (mod\ 12)$$
This means 14 and 2 have the same remainder after dividing by 12. If two such numbers have the same remainder, we say they are congruent mod 12.
Let's look at one more example. If it's 2:00, then 5 hours ago the clock was showing 9:00. And in 7 hours, it will also show 9:00.
That's because the numbers -5 and 7 are also congruent mod 12 (they have the same remainder after dividing by 12).
$$-5\equiv 7\ (mod\ 12)$$
When doing arithmetic operations in modular arithmetic, we can replace any number with a congruent number and get the same result. In our case (modulus 12), instead of subtracting 5 from 2, we can add 7 and get the same result: \(2+7=9\).
$$2-5\equiv 2+7\ (mod\ 12)$$
Finding a negative number
To find the negative of a number, we can subtract it from 0
. For example, to find the negative of 7
:
$$0-7=-7$$
This may seem simple, but it will help us understand how Two's Complement works.
Let's do the same in binary using four bits.
Since we only have four bits, we discard any extra leading bits.
If we discard the extra bits, what difference would it make if we subtracted 0111
from 10000
? There is no difference.
Because we can only represent numbers from 0 to 15, when we go outside this range, we simply "wrap around". We are doing modular arithmetic with modulus 16. Since 0000
(0) and 10000
(16) are congruent, we can interchange them in our calculations:
$$0-7\equiv 16-7\ (mod\ 16)$$
In binary:
$$0000-0111\equiv 10000-0111\ (mod\ 10000)$$
There is one more piece to this puzzle. We can rewrite 10000
as (1 + 1111)
:
$$0000-0111\equiv (1+1111)-0111\ (mod\ 10000)$$
Since addition and subtraction have the same precedence, we can change the order of operations:
$$0000-0111\equiv (1111-0111)+1\ (mod\ 10000)$$
Let's see, 1111 - 0111 = 1000
, which is actually 0111
with all bits flipped (1000
is -7 represented as One's Complement). And finally, we have to add 1.
This way we got the Two's Complement representation of -7, which is 1001
.
The operation of \((1111-x)\), where \(x\) is any 4-bit number, will always flip all bits of \(x\). We then have to add 1, so that the result is congruent with \(0-x\) (the negative of \(x\)).
Here is a table of all binary numbers we can represent using four bits, their decimal values, and Two's Complement representations.
As we can see, each Two's Complement representation is congruent with its decimal value.
So, do we really have to 'add 1' to find a Two's Complement?
Let's imagine we were asked to represent -5 as a Two's Complement using 4 bits. From what we've discussed, we should be able to do so without the 'add 1' step.
To find the Two's Complement, we have to find a number that is congruent to -5 mod 16. To do that, we can add 16 to -5, which gives us 11. Write down 11 in binary form (1011
), and we have our answer.
The 'add 1' step is only a side effect of using the 'flipping all bits' process. We like flipping bits because it is easy to do. But, as we showed above, for the congruence to stay valid, we have to add 1.