Applying C - BCD Arithmetic |
Written by Harry Fairhead | ||||||
Tuesday, 18 June 2024 | ||||||
Page 2 of 2
BCD ArithmeticNow we come to the difficult topic of how to perform BCD arithmetic. If you have a lot of arithmetic to do then the best solution is to convert to binary, do the arithmetic and then convert back. This has the advantage that you know how to work with binary and the disadvantage that, if it involves division, you might not get the same answer as a human. In many cases, however, the arithmetic that you want to do is very simple. One way of doing BCD arithmetic is to unpack the nibbles into an array and then add nibbles one by one. The problem with this is that you have to take care of the decimal carries. For example, 9+1 gives you a nibble that isn't a decimal digit i.e. 10 or 1010 in binary or A in hex. To correct this you have to subtract 10 from this nibble and add one to the next nibble so performing a carry. That is, if you add the nibbles together you have to scan for values that are greater than 9 and from each you subtract 10 and add a carry to the next nibble. Notice that as 9+9 is 18 decimal or 0001 0010 you can even overflow 4 bits and so each nibble should be stored in its own byte. Consider for a moment addition of just two BCD digits each one stored in a byte. For example: 9 + 9 = 18 0x09 + 0x09 = 0x12 At this point you need to subtract 10 and carry 1 onto the next nibble. However, if you look, the addition has already put a 1 into the next nibble, it is only the original nibble that is wrong. The reason is that the carry 1 into the next highest nibble has actually carried 16 not 10 from the lower nibble - remember this is implemented as binary. To get the correct BCD we have to return 6 to the lower nibble. 9 + 9 = 18 0x09 + 0x09 = 0x12 + 0x06 = 0x18 If you have implemented BCD arithmetic before, you might have wondered where the mysterious "6" comes from. int result = myBCD1 + myBCD2; if(result>9)result=result+6; You can extend this method so that you can add multiple digits and then correct the result to BCD, but it isn't straightforward as you have to detect the binary carry between the nibbles and add 6 to the lower nibble whenever it has occurred. If we have two packed BCD values in four byte unsigned ints then we can simply add them together: unsigned int myBCD1 = 0x90000; unsigned int myBCD2 = 0x90000; int result = myBCD1 + myBCD2; but the result will be incorrect in any nibble that generated a carry to the next nibble. We need to find out where the carries occur. This we can do because we already know that exclusive or (XOR) is addition without taking the carries into account. So: (myBCD1 ^ myBCD2) is the addition without carry. If we XOR this with the sum that did include a carry there will only be bits set where they differ, i.e bits that result from a carry: (myBCD1 ^ myBCD2)^result This gives a one at every bit that was generated by a carry, but we are only interested in carries from one nibble to the next and these can only be positioned at the first bit of the nibble. To pick just these out we have to use a mask: int carry = (myBCD1 ^ myBCD2)^result & 0x011111110; notice that the first nibble cannot have received a carry. Now we have a carry which has a one in the first bit of any nibble that received a carry from the adjacent nibble. We need to create a mask with a 6 in each position that generated a carry and this we can do using a shift and OR: int sixmask = (carry >> 2) | (carry >> 3); Finally we can add the sixes into the result to correct it: result += sixmask; Notice that you cannot allow a carry in the final nibble - the result is an overflow. You can extend this bit manipulation technique to long long types if you need more digits. You can also make it work for subtraction by using ten’s complement, see the next section. In chapter but not in this extract
Summary
Now available as a paperback or ebook from Amazon.Applying C For The IoT With Linux
Also see the companion book: Fundamental C <ASIN:1871962609> <ASIN:1871962617> Related ArticlesRemote C/C++ Development With NetBeans Getting Started With C/C++ On The Micro:bit To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.
Comments
or email your comment to: comments@i-programmer.info |
||||||
Last Updated ( Tuesday, 18 June 2024 ) |