Applying C - BCD Arithmetic |
Written by Harry Fairhead | |||
Tuesday, 18 June 2024 | |||
Page 1 of 2 We all know that binary arithmetic doesn't always give the answer that a human would get. If you want to do arithmetic like a human you have to use decimal. This is what BCD is all about and it is explained in this extract is from my book on using C in an IoT context. 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> Arithmetic is the forgotten task. We just expect machines to evaluate whatever expression we write and we expect it to get it right – or right enough not to cause a problem. Part of the reason for this unreasonable assumption is the availability and success of floating point arithmetic. However, even floating point arithmetic can give you results that are closer to random numbers than a valid answer if you don’t take care. This chapter isn’t about floating point arithmetic – for that see Chapter 7. Smaller computers often don’t have a hardware floating point unit and if you want to use floating point you have to use a software implementation which is slow. In most cases a better option is to use integer or fixed-point arithmetic which is more appropriate for embedded processors and special digital signal processors, for example. In this chapter we look at the basics of integer arithmetic and the next tackles its extension to fixed-point arithmetic. It is assumed that you know the basics of binary numbers, the bitwise operators and how to use hexadecimal. If you are in any doubt about these topics see: Fundamental C: Getting Closer To The Machine (ISBN: 978-1871962604) In chapter but not in this extract
Decimal Arithmetic with BCDAlthough decimal hardware is rare, there are lots of reason to want to work in decimal in software. For example, binary often doesn't give results that are the same as a human would get doing manual arithmetic. For example, if an expression results in 0.1 in decimal this isn't exactly representable in fixed point binary. However, for integer arithmetic binary gives the same result as decimal arithmetic. A more common reason for needing decimal in small systems is that sensors and displays often make use of it. For example, a sensor might naturally return some decimal digits to represent a temperature, or a numeric display might need to be fed decimal values. You can avoid decimal arithmetic by always converting to binary and then back to decimal as needed but in many cases it is simpler to stay with the representation the device provides. It is also instructive to see that in C and in low-level programming in general all we have are bit patterns and how you interpret them is up to you. Binary Coded Decimal is very simple. The bit patterns 0000 to 1001 are used to code 0 to 9. These bit patterns can be stored one per byte or, packed as BCD, as two digits per byte. Four bits are often referred to as a nibble and so we use one nibble to store a digit. Notice that you are not using the full range of the nibble and often the unused values represent symbols such as plus or minus. To convert a binary value to BCD all you have to do is extract the decimal digits. For example, starting with: int myVal = 123; you can get the least significant digit by taking the remainder on division by 10: myBCD1 = myVal % 10; The remainder of 123 after division by 10 is 3 and so myBCD1 now contains 3. All we now have to do is repeat after removing the least significant digit: myVal = myVal / 10; myBCD1 += (myVal % 10) << 4; The shift by 4 bits is to move the digit into the next nibble. The next digit is extracted in the same way, but this time is shifted 8 bits to move it to the next nibble: myVal = myVal / 10; myBCD1 += (myVal % 10) << 8; Now you have seen how this works, it is easy to convert it into a loop that will convert any positive binary value to BCD: int s = 0; int myBCD1=0; while (myVal > 0) { myBCD1 += (myVal % 10) << s; s += 4; myVal = myVal / 10; } printf("%x\n", myBCD1); It is worth remembering that to convert BCD to an ASCII char you simply have to add 0011 to the start of each nibble. You also have to unpack each nibble into a byte. One way to do this is to shift right and use a mask: char myASCII[5] = {0}; int i=0; while (myBCD1 > 0) { myASCII[3-i] = (myBCD1 & 0x0F) | 0x30; myBCD1 >>= 4; i++; } printf("%s\n", myASCII); To convert to binary you simply proceed as you would with a decimal number, but in this case extracting nibbles for each digit. myVal=0; int p=1; while (myBCD1 > 0) { myVal += (myBCD1 & 0x0F)*p; myBCD1 >>= 4; p=p*10; } printf("%d\n", myVal); |
|||
Last Updated ( Tuesday, 18 June 2024 ) |