I was discussing a project with a young colleague who was trying to make a measurement using an ADC (analog-to-digital converter) and convert this measurement into a voltage to be displayed. He was playing around with the floating-point functions of the compiler. I observed that there was no real need to use floating-point data or math operations. When coupled with a response to a previous blog of mine, this suggested to me that a brief recap on integer arithmetic would not go amiss.
Back in the day, when the 2 kbyte 8048 microcontroller was the latest and greatest thing on the market, and when you were hand-coding or using an assembler (if you were lucky), memory space and execution speed were very high on your list of budgetary limitations. If you had to perform any mathematical processing, you had to consider your approach very carefully.
Firstly, there were no standard libraries readily available. Intel did have one called "Insight" (or maybe "Insite"), but it was expensive to join and you were (or at least, I was) reduced to scouring application notes and design ideas to find that ideal 16x16 multiplication routine. Oftentimes you would have to write your own.
Today some of these really smart tricks appear in books like Hacker's Delight by Henry S. Warren, Jr. If you really want to be impressed, you should look at the work done by Jack Crenshaw in his book Math Toolkit for Real-Time Programming. Today the integer arithmetic functions are either included in the compiler or there are many resources available with the routines, so you don't have to go to the very basics, but you can still avail yourself of the early techniques.
Let me state here and now that I am using the term "integer arithmetic" to cover the mathematical concept of integer and not the C compiler int data-type declaration. As we will see, the data types will have to be selected to suit our ends.
Let's assume that you want to read a 12-bit ADC with a span of 5V. The voltage would be simply given by (N/(Nmax - Nmin))*Vref, where N is the current reading, Nmax is the reading at the maximum voltage, Nmin is the reading at the minimum voltage, and Vref is -- of course -- the 5V of the ADC reference.
As a starting point, we assume the full range of the ADC conversion; hence, Nmax = 4,095 and Nmin = 0. Thus the voltage is given by (N/4,095)*5. With a floating-point calculation, the order of calculation is not significant (at least at the first approximation), but you can still perform this calculation with integer arithmetic and get a respectable result, if you think about what you are doing. Let's assume the number N that we measure is 1,234, so -- using a calculator -- the result is 1.507V. However, if you performed this using integer math with the operations in the order they are written, the integer division 1,234/4,095 will return a zero (any remainder is "thrown away"), and any product involving one or more zeros will result in a zero.
However, if we choose to first multiply the numerator with Vref, this will yield an interim result of (1,234*5) = 6,170. You should have been taught that the number of bits needed to represent a product in binary is the sum of the number of bits of each multiplicand. You need to make sure that the interim variable is correctly declared to handle the maximum number of bits in the result. If we now perform an integer divide by 4,095, we will obtain a result of 1. This is closer to the true answer, but definitely "no cigar."
To Page 2