Wednesday, March 23, 2011

Two's complement examples

My friend suggested that I should talk more about one's complement and endianness. I think that endianness is confusing, so I don't want to talk about it, other than to say that it deals with the order of bytes in a multi-byte number in memory (click the link if you want to get confused more). I will mention one's complement, though, because I think it's interesting.

Two's complement is the system where in order to turn a number into its negative you flip all the bits and add one. One's complement is similar, except you don't add one at the end of the number conversion. For example, in one's complement the number -11 would be represented like this:

0b0000 1011 (that's positive 11)
flip all the bits
0b1111 0100 (and that's -11 in one's complement)

This looks a lot easier, right? Well, the downside is that there's an additional step when adding negative numbers with this representation. After you do the normal addition, you have to look at the final carry-out and add that value back to the one's place of your result. That right there isn't that big of a deal, and adders could be built to automatically do that.

The other bad thing about one's complement is that it's possible to have both positive and negative ZERO. Both 0b0000 0000 and 0b1111 1111 mean "zero" but one of them is positive and one is negative (remember to look at the sign bit to determine whether it's positive or negative). That's weird and it means that we can only represent 255 numbers with a single byte instead of 256 that we can represent using two's complement.

I'm not going to do any examples of one's complement, because it isn't used in real life. Instead, I'm going to do a couple examples of two's complement. First, let's transform positive 56 into negative 56, and back again. I didn't mention it last time, but you can tell the value of a negative two's complement number by repeating the same steps that made transformed it from positive to negative in the first place. Like this:

0b0011 1000 (+56)
flip all the bits
0b1100 0111
and add 1
0b1100 1000 (now we have -56)

Now let's turn that negative number back into a positive:

0b1100 1000 (-56)
flip all the bits
0b0011 0111
and add 1
0b0011 1000 (and we're back to +56)

Now let's subtract 15 from 32 (32-15=?).

Here's 32:
0b0010 0000 (+32)

Now let's figure out what -15 is:
0b0000 1111 (+15)
flip all the bits
0b1111 0000
and add 1
0b1111 0001 (-15)

Now we add them together, because 32 + (-15) is the same as 32-15.

+0b0010 0000 (32)
+0b1111 0001 (-15)
=0b0001 0001 (17)

This time we're going to totally ignore the final carry-out. Look at the sign bit, and notice that it's a 0, that means we ended up with a positive number. In fact, that number we ended up with is 17, which is the right answer. 32-15=17.

Just to review, this is how subtraction is accomplished in real computers, and how negative numbers are represented in real computers. We use two's complement because it lets us represent a wide range of positive and negative values (it doesn't have that silly +0/-0 issue one's complement has), and it is terribly, terribly convenient for allowing us to use regular multi-bit adders to perform subtraction.

I don't have a plan already in my head for what to present next, but if you ever have a recommendation, let me know in the comments.

1 comment:

  1. Seth. This is cool. I've read through all your posts since you mentioned in on Facebook last week, and it's nice to have an idea how this works on this lower level.

    One question I have is how a circuit actually carries out an operation (any operation, even storing or loading a number from memory). I think I understand how program commands can be broken down to these basic binary operations, but the actual mechanics (or physics?) of it is a total mystery to me.

    ReplyDelete