datasheets.com EBN.com EDN.com EETimes.com Embedded.com PlanetAnalog.com TechOnline.com   UBM Tech
UBM Tech

Even more mind-boggling math: Working with signed BCD

-October 05, 2005

In the first column of this series, I introduced the concepts underlying BCD (binary-coded-decimal) representations. In my second column I discussed how we go about adding and subtracting unsigned BCD values. And now we're going to ponder the mysteries of working with signed (tens-complement) versions of BCD numbers.

Setting the scene

In order to wrap our brains around the way math operations work on signed (tens-complement) BCD numbers, it's worth taking a few moments to first remind ourselves how they work with their signed binary (twos-complement) equivalents.

As we know, an 8-bit byte can be used to represent signed binary values that equate to decimal numbers in the range –128 to +127. The way this works is that the most-significant bit—the sign bit—represents a negative quantity of –128, while the remaining bits represent their usual positive quantities ().

Thus, a signed binary value of 11100101 equates to –128 (from the sign bit) + 101 (from the remaining bits) = –27. The advantage of this form of representation is that we can always simply add signed binary values, irrespective of whether they represent positive or negative quantities. For example:

   00111001 + 00011110 = 01010111 [which equates to (+57) + (+30) = +87]

   00111001 + 11100010 = 00011011 [which equates to (+57) + (–30) = +27]

   11000111 + 00011110 = 11100101 [which equates to (–57) + (+30) = –27]

   11000111 + 11100010 = 10101001 [which equates to (–57) + (–30) = –87]

Observe that we've dropped any carry-out values from the above. This is because, in the case of signed binary numbers, the carry-out is of interest only if we're working with multibyte quantities.

Furthermore, we know that we can perform a subtraction operation, like (+7) – (+3) = +4, in decimal by changing the sign of the subtrahend and inverting the sign of the operation. That is, (+7) + (–3) = +4. In binary, the way we change the sign of the subtrahend is to take the twos complement of the number, which we achieve by subtracting it from all 1s and then adding 1. For example, starting with:

   00111001 – 00011110[which equates to (+57) – (+30)]

We take the twos complement of the subtrahend and invert the sign of the operation, which gives us the following:

   00111001 +(11111111 – 00011110) + 1]

Which gives us:

   00111001 + (11100001 + 1)

Which gives us:

   00111001 + 11100010 [which equates to (+57) + (–30)]

Which brings us nicely back to the examples we looked at earlier. One interesting point to consider at this stage is that, in the case of an 8-bit microprocessor working on 8-bit signed binary values, the overflow (O) flag is generated as an XOR of the carry-in and the carry-out from the most-significant bit of the accumulator. If the overflow flag is 0, the result from the operation will fit in the 8-bit field; by comparison, if the overflow flag is 1, the result will be too large or too small to fit in the field.

Working with signed BCD values

Now, as we discussed in the first column in this series, signed BCD values work in a similar manner to their signed-binary counterparts. In the case of an 8-bit byte containing two BCD digits, any value of 5 or above in the most-significant digit represents a negative quantity. For example (assuming the "#" character is used to indicate a BCD number), the BCD values #00 through #49 would be used to represent positive values in the range 0 through +49. A BCD value of #50 actually represents a negative value of –50; a BCD value of #51 represents –50 + 1 = –49; a BCD value of #52 represents –50 = 2 = –48; and so on up to a BCD value of #99, which represents –50 + 49 = –1. Thus, using this scheme, our two-BCD-digit byte can be used to represent decimal values in the range –50 to +49 ().

In the second column in this series, we discussed how to add together two bytes containing unsigned BCD values. Well, we use exactly the same techniques with signed BCD values. As a simple example, let's start by adding two positive values:

   #27 + #15 = #42 [which equates to (+27) + (+15) = +42 in decimal]

We can visualize the way this works as follows. First of all we add the two least-significant BCD digits 7 and 5, which returns a result of 12. This means that the least-significant digit of the result is set to 2, and we have a carry-out to the most-significant digit. Thus, when we add the most-significant digits together, we have 2 + 1 + (1) = 4 (where the 1 in parentheses is the carry generated by the addition of the least-significant digits).

Now let's get a little braver. Let's suppose we wish to add a negative value to a positive value, as follows:

   #27 + #72 = #??

Remember that a signed BCD value of #72 equates to –50 + 22 = –28 in decimal, so the above equation equates to (+27) + (–28) = ? in decimal. As usual, we first add the two least-significant BCD digits 7 and 2, which gives a result of 9 with no carry-out to the most-significant digit. Next, we add the most-significant digits 2 and 7 together, which again gives 9 with no carry out. So the final result from this test case is:

   #27 + #72 = #99 [which equates to (+27) + (–28) = –1]

Hurrah, it works! And what about subtracting signed BCD values? Well, once again we achieve this by changing the sign of the subtrahend and inverting the sign of the operation. In the case of signed BCD, the way we change the sign of the subtrahend is to take the tens complement of the number, which we achieve by subtracting it from all 9s and then adding 1. For example, starting with:

   #27 – #35 = ?? [ which equates to (+27) – (+35) = ??]

We take the tens complement of the subtrahend and invert the sign of the operation, which gives us the following:

   #27 + (#99 – #35 + 1) = ??

Which gives us:

   #27 + (#64 + 1) = ??

Which gives us:

   #27 + (#65) = ?? [which equates to (+27) + (–35) = ??]

So let's perform this new calculation. We first add the two least-significant BCD digits 7 and 5, which returns a result of 12, which gives us 2 in the least-significant digit and a carry-out of 1 to the most-significant digit. Next, we add the most-significant digits together, which gives us 2 + 6 + (1) = 9 (where the 1 in parentheses is the carry from the least-significant digit). So we now have:

   #27 + (#65) = #92 [which equates to (+27) + (–35) = –8]

It's just like magic isn't it?

A little question…

Finally, I'd like to leave you with little poser to ponder. As we noted earlier, in the case of signed binary (twos-complement) representations, the overflow flag is generated as an XOR of the carry-in and the carry-out from the most-significant bit of the accumulator.

They say that a little knowledge is a dangerous thing, and they (whoever "they" are) are right, because—based on my knowledge of binary—when I started playing with signed (tens-complement) BCD , I sort of assumed the overflow flag would be generated as an XOR of the carry-in and the carry-out from the most-significant BCD digit. But this doesn't work. Consider the following:

   #29 + #01 = #30 [which equates to (+29) + (+1) = +30 in decimal]

In this case we have a carry-out from the least-significant digit (which is, of course, a carry-in to the most-significant digit) but no carry-out from the most-significant digit. Thus, if we generate the overflow flag as an XOR of the carry-in and the carry-out from the most-significant BCD digit, then in this case we get an overflow of 1, which is incorrect.

It took me days and days to work this out. So where did I make my big mistake? Tune in next time.

Clive "Max" Maxfield is the co-author of "How Computers Do Math" (ISBN: 0471732788) featuring the pedagogical and phantasmagorical virtual DIY Calculator. In addition to being a hero, trendsetter, and leader of fashion, Max is widely regarded as being an expert in all aspects of computing and electronics (at least by his mother).

Loading comments...

Write a Comment

To comment please Log In