Positive and Negative Two Complement Numbers

Negative Numbers: Two's complement  representation

So far, we've just used positive numbers. In decimal, we use a minus sign to indicate a negative number. But the CPU and memory just know 1's and 0's, that is all. So how do we determine a negative number from hexadecimal or binary representation.
  1. All of the values in a computer are of some fixed length of bits. In an HC11, most are 8 bits, and some are 16 bits. But we always know the size of a register or memory. This is important: values are always a fixed number of bits.
  2. One idea is to take the leftmost bit, and interpret it as a sign bit. That is, if the left bit is a 0, the number is positive, and if the left bit is one, the number is negative.
    1. 8-bit example: 00001011 is positive decimal 11, and 10001011 is decimal -11.
    2. But, now we would need electronics to treat the leftmost bit as a special bit.
  3. An ingenious solution: the 2's complement representation (2C)
    1. Take the positive binary number, complement (flip to opposite) all the bits, then add one
    2. Thus, decimal -11 is found by:
      1. taking positive decimal 11, which is 00001011
      2. complementing it, which gives us 11110100 (each bit is opposite)
      3. then adding 1, which gives us 11110101
      4. then, decimal -11 is 8-bit binary 11110101
    3. 2C still has a sign bit: a leftmost 1 means negative, a leftmost 0 means positive
    4. But arithmetic can be done completely ignoring whether a number is signed or not.
    5. That means (important): the CPU doesn't care if you are using signed numbers or not!

Modulo Arthmetic

Here's another related problem: we only have fixed-length registers in a computer. In the case of the hc11, the registers that we use for arithmetic (the A register and the B register) are only 8 bits wide. So what happens if we add something like

 a3
+b4?

The main thing is, we get a result that won't fit. The fix for this is to always do modulo arithmetic: so any arithmetic operation using an 8 bit register is performed mod 256. We can actually turn this problem to our advantage, if we're clever about it. In order to fit this example on the blackboard, let's assume 3 bit numbers, so we have the numbers 0 through 7 and all arithmetic is mod 8 (or radix 8).

Let's make a number line. Unfortunately, since 0 has to follow 7, it can't be a line; it has to be a circle. Now, adding goes clockwise on the circle, and subtracting goes counterclockwise. Here's a picture of the number circle, showing the circle, the numbers on it in decimal, the same numbers in binary, and which direction to go for addition and subtraction.

Question: If I go from 3 to 1, can you tell whether I did it by subtracting 2, or by adding 6? Well, no you can't. Now, here's an idea: any time we want to subtract some number n, we can instead add (8-n). And that means that the way we represent a negative number ``-n'' is by using (8-n) instead.

Now, we'll let the lower half of the numbers of our circle, 0, 1, 2, 3, represent themselves, and the upper half of the numbers of our circle, 4, 5, 6, 7, represent negative numbers, where the negative number is the number of digits we are subtracting from 0. Therefore, the number 7 is the negative number -1 because it is the first slot to the left of zero, etc. That means we can tell a positive number from a negative number by the most significant bit: we'll call this the Sign Bit. When that bit is 0, we will call the number positive and when the bit is 1, we will call the number negative. So now it looks like this:

One last wrinkle: if we have to subtract and negate by taking 8-n, we haven't bought ourselves anything: we still have to subtract. But remember that 8-n = (7-n)+1. And 7-n can be calculated easily by just inverting each bit in the pattern for n! We can just negate every bit in n and that equals 7-n for all n.

Converting from Decimal to another Radix

Suppose we want to convert a negative decimal number to hexadecimal. Take -97, and convert it to 8 bit hexadecimal, for example. Here are the steps:
  1. Remember that it's negative.
  2. Use the division method to convert the magnitude to hexadecimal:

    OldRadixNewDigit
    97 166 1
    6 160 6

    So we get 6116.
  3. Convert 6116 to binary by just writing out the nibbles.
  4. Invert the bits - replace every 1 with a 0, and every 0 with a 1. Working in hexadecimal, this is equivalent to subtracting every digit from f. Since we're assuming a 8 bit word, we need to subtract from ff (you actually need to subtract from enough f's to fill out the word. If it were a 16 bit word, we'd need ffff). ff - 61 = 9e.
  5. Add 1. 9e + 1 = 9f.
You can check your work by adding your result from step 1 to your final result. You should get 0, with a carry-out.

Converting to Decimal from some Radix

Now suppose we have a number such as 11011110 that we want to convert from signed eight-bit binary to decimal. This time, the steps are as follows:
  1. Look at the most significant bit. Since it's a 1, we'll need to negate the number. If it were a 0, we'd skip to step 4.
  2. Invert all the bits. this turns it into 00100001.
  3. Add 1. That will give us 00100010.
  4. Use the multiplication method to convert it to decimal:
    Old Digit New Radix
    0 0 0 2
    0 0 0 2
    0 1 1 2
    2 0 2 2
    4 0 4 2
    8 0 8 2
    16 1 17 2
    34 0 34  
  5. Since the number is negative, we get -34.