Weird float calculation result

Hi,

I just encountered really weird issue when I multiply a float var by 10 and store the result as integer inside a loop.

Some results are wrong. Starting from value of 2.4 the result are wrong.

This only happens when it runs inside FOR loop. What is wrong with my FOR loop? Shouldn’t I use float counter for looping?

Here is my code:

void setup() {
Serial.begin(9600);

for (float n = 0.0;n<5;n=n+0.1){
int i = n * 10;
Serial.print(n);
Serial.print(" = ");
Serial.println(i);
}
}

void loop() {

}

Thx
Bronson

weird-float.ino (188 Bytes)

What is “wrong” with the values?

aarg:
What is "wrong" with the values?

Thx for the quick reply.

Here is the snippets from my Serial Monitor:
2.10 = 21
2.20 = 22
2.30 = 23
2.40 = 23
2.50 = 24
2.60 = 25
2.70 = 26
2.80 = 27
2.90 = 28
3.00 = 29
3.10 = 30
3.20 = 31
3.30 = 32
3.40 = 33
3.50 = 34
3.60 = 35
3.70 = 36
3.80 = 37
3.90 = 38
4.00 = 39
4.10 = 40
4.20 = 41
4.30 = 42
4.40 = 43
4.50 = 44
4.60 = 45
4.70 = 46
4.80 = 47
4.90 = 48
5.00 = 49

Starting from value of 2.4, the results are wrong.

Regards,
Bronson

(deleted)

spycatcher2k:
Why use floats? Use an INT with a little bit of maths the scale it down.

I'm just curious what may cause this miscalculation. Why doesn't it happen outside loops?
This also happens inside WHILE loop.

Bronson

It is NOT a mis-calculation! YOU are the one that is wrong!

Mark

Assigning to an int truncates, rather than rounding.
Add 0.5

Print the value of i to 6 decimal places. You will instantly see what the problem is.

While 1/10 can be exactly represented in base 10, it can NOT be exactly represented in binary, which is how all computers store numbers.

This is not how to do loops with floats:

  for (float n = 0.0;n<5;n=n+0.1){

This might be a better loop:

  for (float n = 0.0;n<4.95;n=n+0.1){

Remember decimal fraction values are not exactly represented in floating point which are
binary fractions. Thus 0.1 * 10 != 1.0 (or rather its not guaranteed to be equal).

So the loop end condition was hanging on a knife-edge when comparing a multiple of 0.1 against
5.0.

Anyway the other problem as pointed out above is that did not use round() when converting to int, which
is usually the way to fix things:

 int i = n * 10;

Will hit the inexactness issue mentioned above some of the time - its basically undefined/ill-defined.

 int i = round (n * 10);

Does what you want and will be far more robust.

The whole loop though is wrong - you should iterate with an integer, convert in the body to a float:

  for (int i = 0; i < 50 ; i++){
    float n = i / 10.0;   // this is the only step with any imprecision now.
    Serial.print(n);
    Serial.print(" = ");
    Serial.println(i);
  }

Exercise for the reader: Why not change that second line to:   float n = 0.1 * i; ?

To spycatcher2k, westfw, PaulS and MarkT: Thanks for all your time & efforts.

Using "int i = round (n * 10);" solves the problem. Next time I will try not to use float var whenever possible.

holmes4:
It is NOT a mis-calculation! YOU are the one that is wrong!

Mark

To Holmes4: Why so hostile? FYI, 2.40*10 = 24 not 23. But thanks for your time anyway.

Regards
Bronson

Bronson_alex:
To spycatcher2k, westfw, PaulS and MarkT: Thanks for all your time & efforts.

Using "int i = round (n * 10);" solves the problem. Next time I will try not to use float var whenever possible.

To Holmes4: Why so hostile? FYI, 2.40*10 = 24 not 23. But thanks for your time anyway.

Regards
Bronson

What he was trying to get at was that you think you put the exact value 2.4 into that float. But floats don't hold exact values. They hold "close enough" values. So what he meant was that you were wrong to think that particular float times 10 would necessarily equal 24.

To Holmes4: Why so hostile? FYI, 2.40*10 = 24 not 23. But thanks for your time anyway.

2.40 * 10 does equal 24

But 2.3999999 will print as 2.40, but 2.3999999 * 10 is NOT 24.

holmes4:
It is NOT a mis-calculation! YOU are the one that is wrong!

Mark

But its the computer that's wrong, of course. IEEE is inaccurate. The only fault is assuming that its easy
to be exact in mechanical calculation schemes for uncountable number types.

The only fault is assuming that its easy
to be exact in mechanical calculation schemes for uncountable number types.

So, how does that make the computer wrong? The computer did not make the assumption that the numbers it is storing are stored exactly.

Because it cannot divide by 10 for instance... :slight_smile:

(decimal 10, to be precise!)

Because it cannot divide by 10 for instance... :slight_smile:

Strange. My computer can.

It does not ASSERT that the result is exact, when the division involves floats, but it CAN divide by 10.

If you've ever used Common Lisp, you'll miss the automatic upgrading to rationals from integers on
division - Common Lisp can divide by any integer and doesn't overflow (unless there's insufficient RAM
to hold the result). However it has limits, many maths functions return floats...

PaulS:
Strange. My computer can.

It does not ASSERT that the result is exact, when the division involves floats, but it CAN divide by 10.

Getting the wrong result is failure, mathematically speaking.

MarkT:
Getting the wrong result is failure, mathematically speaking.

So, it is impossible to divide 1 by 3, because you can't express the result exactly?

Not in decimal, but it is ok with fractional numbers (is that the correct term?) 1/3.

Just because the silicon only know binary, there is no problem for software to perfectly handle decimal. Or fractions. Even some quite cheap calculators can handle fractions.