1.06 is not a float. The closest float is 1.059999942779541015625. If
you multiply that by 100 you get a number that, again, is not a float.
Rounding to the nearest float yields 105.99999237060546875, which is the
result of the expression ver * 100, and just one ULP short of 106.
Yes, floating point computations do quite usually involve rounding
steps.
Casting to an int implicitly rounds towards zero, and you get 105,
which is the correct result. Correct according to the rules of IEEE 754
arithmetics.
You may want to round() to the nearest integer before the cast.
Variable ver can be any decimal in this format x.xx
No, a float cannot be “any decimal” in this format. Floats are stored
in binary, and most decimal numbers (numbers that can be written with a
finite number of decimal digits) cannot be written in binary with a
finite number of bits.
Except for a few values (namely the multiples of 0.25), ver can only
store an approximation of the decimal number.
Converting float to int
Convert float to int error - Arduino Stack Exchange
Converting float to int by removeing decimal point
arduino - C embedded convert float to int - Stack Overflow
Videos
LED_CYCLE_TIME is zero because you don't use floating point division ((1 / F_LEDS) / 2 is (1 / 5) / 2, but 1 / 5 == 0, so it's 0).
Just use doubles: #define LED_CYCLE_TIME (0.5 / F_LEDS)
And you also need some extra brackets around your defines, since currently OVERFLOWS_PER_CYCLE is defined as (unsigned int)((1 / F_LEDS) / 2 / 1 / F_CPU / 256.0), which does the division left-to-right instead of in the correct order.
So your corrected code:
#define OF_FREQUENCY (F_CPU / 256.0)
#define SECONDS_PER_OF (1 / OF_FREQUENCY)
#define F_LEDS 5
#define LED_CYCLE_TIME (0.5 / F_LEDS)
#define OVERFLOWS_PER_CYCLE (unsigned int)(LED_CYCLE_TIME / SECONDS_PER_OF)
The arithmetic can be considerably simpler and can be performed without the need for floating point.
Consider that LED_CYCLE_TIME is:
1 / (2 * F_LEDS)
and that you are dividing that by SECONDS_PER_OF. But that is the same as multiplying by the reciprocal of SECONDS_PER_OF, and you already calculated that as OF_FREQUENCY. So now you have:
1 / (2 * F_LEDS) * OF_FREQUENCY
which is the same as:
OF_FREQUENCY / (2 * F_LEDS)
So what you end up with in code is:
#define OF_FREQUENCY (F_CPU / 256)
#define F_LEDS 5
#define OVERFLOWS_PER_CYCLE (OF_FREQUENCY / (2 * F_LEDS))
Or better:
#define LED_PRESCALER 256
#define F_LEDS 5
#define OVERFLOWS_PER_CYCLE (F_CPU / (LED_PRESCALER * 2 * F_LEDS))
Which given F_CPU == 16000000 is 6250 and requires no floating point.
With some inspiration from timemage's comment, I decided in the long run to implement my own power function that takes two int arguments and returns an int. Rather than use the pow function in the <math.h> library which returns a double when I only need an int.
int power(int x, int y) {
return y == 0 ? 1 : x * power(x, y - 1);
}
Now the program works as intended!
As explained by @chrisl in a comment, the issue is that pow() does not
return an exact result, only an approximation. It works fine with
compile-time constants because in this case it is evaluated at compile
time, by the compiler, on you PC.
Simple solution: replace the cast to int with round():
int multiplier = round(pow(10, argc - 1));
This works, but is awfully inefficient, as pow() involves the
computation of both an exponential and a logarithm, both very expensive
on an AVR-based Arduino. The int-only function in your own answer is
certainly better. However, it is generally advised to avoid recursion on
low-memory Arduinos like the Uno. Prefer an iterative algorithm if you
can.
Also, the complexity of you int-only function is O(y). There is a well-known algorithm for integer powers that goes like O(log(y)):
int power(int x, int y)
{
int z = 1; // Invariant: result = x^y * z
while (y) {
if (y & 1) z *= x;
y >>= 1;
x *= x;
}
return z;
}
Maybe I am nitpicking, as your y cannot go beyond 5 without
overflowing the result...
An integer is a whole or natural number. Computers use integers for counting and comparisons. Computers can count precisely using integers and comparisons of two integers can be absolutely true or false.
To make a float or floating-point number, a computer uses two integer numbers. It uses one integer as the mantissa and the other as the exponent. Computers use floats for calculations involving very large, very small or fractional values. In other words the set of real numbers. Computers can not count very well using floats. Computer can not even compare two floats very well. That is to say, you may get different results from different computers when testing if two different floats are the same or not. This is due to rounding error.
Consider that the set of real numbers between 0 and 1 to be infinite. However, intuitively, we know computers can not keep track of an infinite number of unique values between 0 and 1. After all, computers use a float to do this and a float has a finite number of bits in it's mantissa and exponent. The difference, if any, between the actual real number from, say, a calculation and the next possible float value is commonly referred to as the roundoff error. In a program, a difference, for example, in the order of operation is enough to cause different roundoff errors to occur resulting in two slightly different float value results.
Rounding errors are what we end up with for allowing float values to grow very large or very small or to contain factional amounts. Fortunately, floats are exactly what we need when computers are asked to calculate very large, very small or fractional numbers.
In embedded programming we rarely use floats. They take up more of our limited RAM space than integers. And it is rare that we need to calculate very large or very small numbers. Usually, in embedded programming, we are counting events or measuring sensors. Usually integers are preferred or are sufficient for our purposes.
Addressing your specific application (pedometer):
It is anticipated you would prefer to track distances in miles. And it is practical to assume a good pedometer displays factional miles. You can use floats to calculate this value. A rigorous programmer would cast their integers as floats when mixing them in equations to make it clear to the compiler what is desired.
"int" means integer. It's either one whole number (forgive me, mathematicians, for the sloppy definition!) or the next or previous.
A "float" is a floating-point number - that is, a number and part of a number.
3 is an int
3.14 is a float
If you need to store/represent a value that can be between integers, you could use a float.
Floats use more RAM than integers, and there is a limit to the precision they can represent. Don't use a float unless you have a need.