Two's complement is a clever way of storing integers so that common math problems are very simple to implement.
To understand, you have to think of the numbers in binary.
It basically says,
- for zero, use all 0's.
- for positive integers, start counting up, with a maximum of 2(number of bits - 1)-1.
- for negative integers, do exactly the same thing, but switch the role of 0's and 1's and count down (so instead of starting with 0000, start with 1111 - that's the "complement" part).
Let's try it with a mini-byte of 4 bits (we'll call it a nibble - 1/2 a byte).
0000
- zero
0001
- one
0010
- two
0011
- three
0100
to 0111
- four to seven
That's as far as we can go in positives. 23-1 = 7.
For negatives:
1111
- negative one
1110
- negative two
1101
- negative three
1100
to 1000
- negative four to negative eight
Note that you get one extra value for negatives (1000
= -8) that you don't for positives. This is because 0000
is used for zero. This can be considered as Number Line of computers.
Distinguishing between positive and negative numbers
Doing this, the first bit gets the role of the "sign" bit, as it can be used to distinguish between nonnegative and negative decimal values. If the most significant bit is 1
, then the binary can be said to be negative, where as if the most significant bit (the leftmost) is 0
, you can say the decimal value is nonnegative.
"Sign-magnitude" negative numbers just have the sign bit flipped of their positive counterparts, but this approach has to deal with interpreting 1000
(one 1
followed by all 0
s) as "negative zero" which is confusing.
"Ones' complement" negative numbers are just the bit-complement of their positive counterparts, which also leads to a confusing "negative zero" with 1111
(all ones).
You will likely not have to deal with Ones' Complement or Sign-Magnitude integer representations unless you are working very close to the hardware.
It's done so that addition doesn't need to have any special logic for dealing with negative numbers. Check out the article on Wikipedia.
Say you have two numbers, 2 and -1. In your "intuitive" way of representing numbers, they would be 0010
and 1001
, respectively (I'm sticking to 4 bits for size). In the two's complement way, they are 0010
and 1111
. Now, let's say I want to add them.
Two's complement addition is very simple. You add numbers normally and any carry bit at the end is discarded. So they're added as follows:
0010
+ 1111
=10001
= 0001 (discard the carry)
0001
is 1, which is the expected result of "2+(-1)".
But in your "intuitive" method, adding is more complicated:
0010
+ 1001
= 1011
Which is -3, right? Simple addition doesn't work in this case. You need to note that one of the numbers is negative and use a different algorithm if that's the case.
For this "intuitive" storage method, subtraction is a different operation than addition, requiring additional checks on the numbers before they can be added. Since you want the most basic operations (addition, subtraction, etc) to be as fast as possible, you need to store numbers in a way that lets you use the simplest algorithms possible.
Additionally, in the "intuitive" storage method, there are two zeroes:
0000 "zero"
1000 "negative zero"
Which are intuitively the same number but have two different values when stored. Every application will need to take extra steps to make sure that non-zero values are also not negative zero.
There's another bonus with storing ints this way, and that's when you need to extend the width of the register the value is being stored in. With two's complement, storing a 4-bit number in an 8-bit register is a matter of repeating its most significant bit:
0001 (one, in four bits)
00000001 (one, in eight bits)
1110 (negative two, in four bits)
11111110 (negative two, in eight bits)
It's just a matter of looking at the sign bit of the smaller word and repeating it until it pads the width of the bigger word.
With your method you would need to clear the existing bit, which is an extra operation in addition to padding:
0001 (one, in four bits)
00000001 (one, in eight bits)
1010 (negative two, in four bits)
10000010 (negative two, in eight bits)
You still need to set those extra 4 bits in both cases, but in the "intuitive" case you need to clear the 5th bit as well. It's one tiny extra step in one of the most fundamental and common operations present in every application.
Best Answer
Take the positive value, invert all bits and add one.
It makes easy to add 7 in -7 and came up with a zero. The bit operations are fast.
How does it make it easy?
Take the 7 and -7 example. If you represent 7 as
00000111
, to find -7 invert all bits and add one:Now you can add following standard math rules:
For the computer this operation is relatively easy, as it involves basically comparing bit by bit and carrying one.
If instead you represented -7 as
10000111
, this won't make sense:To add them, you will involve more complex rules like analyzing the first bit, and transforming the values.
And don't forget what @trashgod said, in 2's complement you have only one zero. To check it:
Differently from
00000000
(0) being equal to10000000
(-0)