I currently use this to iterate over digits of an integer Works pretty well, except for a single 0 input, which is to be expected.
void hc595_number(unsigned int number) {
while(number) {
hc595_digit(number % 10);
number /= 10;
}
}
However what I'm now failing to do (because % doesn't take a float and an int) is iterate, the same way over a float's digits. I would need to also detect the point in the float and do something a bit different for the next digit, instead of hc595_digit
, as I can do for the normal digits.
So, basically for 12.4
, I'd need to call hc595_digit
on the 4
, then record the next thing being the point, and then for the 2
, call a different function.
What is the easiest way to implement this in AVR-C
Binary-based floating-point numbers do not have decimal digits the way you might think.
Even integers are not stored as decimal digits. They are represented with binary. When you using % 10
and / 10
, you are calculating a decimal representation for them. (If they were stored with a decimal representation, C would likely have some operator to access the digits, a sort of subscript-operator like x[3]
to get the third digit of x
. Instead, you are using calculations, like % 10
, to compute the digits.)
Many C implementations use the IEEE-754 basic 64-bit binary format for double
. Suppose your C implementation does, and you execute x = 12.6;
. Then the value of x
is not 12.6, because 12.6 cannot be represented in this format. Instead, 12.6 is rounded to a representable value. If it is correctly rounded to the nearest representable value, the result is 12.5999999999999996447286321199499070644378662109375. When you correctly compute the first digit after the decimal point, you will get 5, not 6.
It is possible to write code to get these digits. In a good C implementation, the easiest way is to use snprintf
to format the number. One can also write calculations to compute these digits, and C has fmod
, remainder
, remquo
, and modf
functions that serve purposes similar to the %
operator for integers. However, multiplying by 10 in a binary-based floating-point format is problematic, because multiplication, like most floating-point operations produces a result that is the real-number mathematical result rounded to the nearest representable value. Simply multiplying by 10 will trying to compute digits will introduce errors and give incorrect results.
The proper approach depends on why you are trying to compute a decimal representation for a floating-point number, and what parameters you have regarding bounds of the numbers, number of digits desired, how accurate the decimal representation must be, and so on.