If you have been reading any of my previous posts, by now you should be becoming a bit more comfortable with binary numbers. Up until this point though, we’ve been talking about only positive numbers. The logical question that follows is what do we do for negative numbers. In todays post we’re going examine this question and look at signed numbers (numbers that can be both positive and negative) and look at the three different approaches that can be used to represent them in binary.
Table of Contents
Sign-Magnitude
The first approach to representing signed binary numbers is a technique called Sign-Magnitude.
In the Sign-Magnitude approach the most significant bit (the left most bit) is used to represent the sign of the number. If the bit is set to 0 the entire number is viewed as positive. If it is set to 1 the entire number is viewed as negative.
All the remaining bits in the number are then used to represent the size or magnitude of the number (much as we’ve already been talking about up until now with unsigned binary numbers).
Now, there are both positives and negatives with using the Sign-Magnitude approach (excuse the pun). On the positive side, it is easy to implement. Add a bit to represent the sign of the number and you’re all set. On the downside though this simplicity causes complications.
With the Sign-Magnitude approach, there are two representations of zero (i.e. 0000 0000 and 10000 0000) and performing arithmetic with binary numbers represented as in this manner can be pretty complex.
For example, adding two positive numbers together isn’t a problem (unless the result overflows into the sign bit) but adding a positive and negative number gives completely the wrong answer. For this reason, the Sign-Magnitude approach isn’t really used that often to represent binary numbers. Lets look at our next approach, something called One’s Complement and see if that does any better.
One’s Complement
As with the Sign-Magnitude, One’s Complement also uses the most significant bit to represent the sign of the number and as with Sign-Magnitude if it is set to 0 the overall number is viewed as positive and if set to 1 the overall number is viewed as negative.
This time though, if you want to convert a number from one sign to another (say from positive to negative), instead of simply flipping the sign bit, you invert ALL the bits in the number. That means the 0’s become 1’s and the 1’s becomes a 0’s.
For example if we had the binary number 01110110_{2} and wanted to find it’s One’s Complement equivalent (basically the opposite) we would invert all the bits and get 10001001_{2}.
As with the Sign-Magnitude there are both advantages and disadvantages to One’s Complement.
One of the big advantages is that binary arithmetic is much simpler. Numbers can now be added easily regardless of whether they are positive or negative. The only caveat to this is that if we do and we need to carry out a bit on the left-hand side of the bits we have available, we simply add this as a 1 to the least significant (right-hand) bit (this is called an end around carry).
The disadvantages remain though. As with the Sign-Magnitude approach, One’s Complement still suffers from having two representations of zero (00000000 and 11111111) and that in turn makes some arithmetic tricky. In summary, One’s Complement is a significant improvement on Sign-Magnitude, but is still not quite there. That’s where our next approach Two’s Complement comes in.
Two’s Complement
The Two’s Complement approach to representing signed numbers is almost exactly the same as the One’s Complement approach and is the most widely adopted method of representing negative binary numbers used today.
As with One’s Complement, the most significant bit in Two’s Complement is used to represent the sign of the number and again, if it is set to 1 the number is viewed as negative and if it is set to 0 it is viewed as positive.
Also, as with One’s Complement, if we want to find the complement of a given binary number, all we do is invert all the bits in the number.
Where One’s Complement and Two’s Complement differ though i. what we do next. In Two’s Complement, once the bits have been inverted, we take a vital step of adding 1 to the resulting number.
In addition to this, if we need another, more significant, column we simply truncate the number, dropping the extra 1 that would have been carried.
Let’s look at a couple of examples. First we’ll look at an example were we don’t need to worry about this truncation.
Imagine that we had the binary number 01111111_{2} and wanted to find the Two’s Complement equivalent. Given the steps we outlined above, the first thing we would do was to invert all the bits so the 0’s become 1’s and the 1’s become 0’s. That would give us a new number: 10000000_{2}.
Once we have flipped the bits, we perform the second step of Two’s Complement, that of adding 1 to our new number. If we do that we get 10000001_{2}.
That’s it. That’s all there is to it. We have our Two’s Complement representation!
Now how about a more complicated example. Imagine this time we had the binary number 00000000_{2} and we follow the same steps again.
First we invert the bits (to get 11111111_{2}). We then add 1.
In this case though we would need an additional column to hold the carried bit (normally the answer would be 1 0000 0000_{2}) but as I mentioned above, in Two’s Complement, when this happens, we simply drop that carried bit. We therefore get the result 00000000_{2}
Let’s have a look at a few more examples. In each, read across the row to see the different steps. For simplicity I’ve also included our two examples above:
- Step 1 – Flip the Bits
- Step 2 – Add 1 to get the Two’s Complement Representation
Bits | Step 1 | Step 2 |
01111111 | 10000000 | 10000001 |
01111110 | 10000001 | 10000010 |
00000001 | 11111110 | 11111111 |
00000000 | 11111111 | 00000000 |
11111111 | 00000000 | 00000001 |
11111110 | 0000 0001 | 00000010 |
10000000 | 01111111 | 10000000 |
10000001 | 01111110 | 01111111 |
10000010 | 01111101 | 01111110 |
Note how in the fourth example in the table above we drop or truncate the bit that we would have carried. Also notice how in the seventh example, the sign bit of the two’s complement representation actually changes.
So what are the advantages of Two’s Complement. Well, the first thing is that basic addition and subtraction (we’ll get to subtraction in another post) of both positive and negative numbers result in the correct answer.
A second major advantage, and the one that makes Two’s Complement preferential over a One’s Complement, is that there is only a single representation of zero. Take another look at the fourth example in the table above and you’ll see what I mean. The truncation rule we talked about is key to this and ensures that regardless of what we do we have only one way of representing zero. We’ll take a look at this in our next set of examples.
Converting Signed Binary Numbers into Decimal
Let’s have a look at a few more examples, this time we’ll be relating our binary numbers back to their decimal equivalents so we get a clearer understanding of what is going on. The steps for converting a Two’s Complement number into decimal are simple.
First we check the sign bit.
As I’ve said before, if the bit is 0 we have a positive number. If this is the case, we simply convert all of the remaining bits as we would for any positive binary number (I’d suggest using the Multiple Method I outlined in one of my previous post but use whichever technique you are most comfortable with).
If however, the sign bit is a 1, the number is a negative number and in this case we take a slightly different approach.
If our number is negative, we take the Two’s Complement of that negative number, applying all the same rules as we’ve just learnt (flipping the bits and adding 1).
We then convert that result into decimal as you normally would and finally, we add a minus sign to the result.
Let’s look at a couple of examples so you get comfortable with it. All of them have their negative sign bit set:
- Step 1 – Flip the Bits
- Step 2 – Add 1
- Step 3 – Convert to Decimal
- Step 4 – Add the minus sign to get the decimal equivalent
Binary Bits | Step 1 | Step 2 | Step 3 | Step 4 |
11111111 | 00000000 | 00000001 | 1 | -1 |
10101010 | 01010101 | 01010110 | 86 | -86 |
10000000 | 01111111 | 10000000 | 128 | -128 |
The Effects of Signed Numbers on Number Ranges
Take another look at the table above. From my earlier post you should now be familiar enough with binary numbers to work out the minimum and maximum numbers that can be stored as an unsigned number using 8 bits of data.
Have a think about it. Can you work it out?
At the lower end, assuming none of the bits are being used to represent the sign of the number we have none of the bits set. This represents the number 00000000_{2} = 0_{10}. At the upper end we have all the bits set which represents the number 11111111_{2} = 255_{10}.
If we apply Two’s Complement though and use one of the bits to represent the sign of the number the distribution of those numbers around zero changes.
Assuming we still have the same 8 bits, at one end we start with 10000000_{2} = -128_{10} (work through the steps above again if you are struggling to understand this conversion) and at the other end we have 01111111_{2} = +127_{10}.
As a side note, also notice how we can represent slightly more numbers on the negative side than we can on the positive side.
The range of numbers that can be stored within a given set of bits is extremely important in computer programming and whether those numbers are signed (i.e positive or negative) or unsigned (positive only) can have a dramatic effect on the maximum and minimum numbers that can be stored. In todays post we’ve looked at the three main approaches for representing signed numbers in binary and have seen that although Sign-Magnitude and One’s Complement are interesting approaches, Two’s Complement is the most useful and widely used approach for representing signed numbers in modern computing. Keep this in mind as we move forward in our binary investigations.
Image Source: https://unsplash.com/photos/cl16g4_j_4Q