Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any risk of using float variables as loop counters and their fractional increment/decrement for non "==" conditions?

Are we safe to use floats as loop-counters and to increment/decrement them by fractional amounts at each iteration,like in the seemingly risk-free program below?Of course I know that using floats as operands for the == operator is a dumb thing to do.But what's wrong with using floats as operands for other comparison operations for "normal" purposes? By "normal" I mean that,well,even though floats may not be the exact numerical representation of the number,but isn't a variation like 0.000000001 irrelevant and can be ignored in most cases? (For example in the following program that isn't even apparent)

But that said, here is my apprehension.Suppose the representation isn't exact and 5.0 is actually 4.999999.So as we go on decrementing by 0.5 at each iteration,the last comparison with 0 may turn out false and the loop may exit due to a difference of 0.000001,and the last line of current output will not be displayed. I hope you are getting my drift.How wrong am I?

#include<stdio.h>

int main(void)
{
float f;

for(f=5.0;f>=0;f-=0.5)
printf("%f\n",f);
}

Output:

5.000000
4.500000
4.000000
3.500000
3.000000
2.500000
2.000000
1.500000
1.000000
0.500000
0.000000
like image 256
Rüppell's Vulture Avatar asked May 16 '13 19:05

Rüppell's Vulture


1 Answers

No, it's not safe, for the reasons given in your very question. Consider this:

#include<stdio.h>

int main(void) {
  float f = 1.0;

  for(;f>0;f-=0.1)
     printf("%f\n",f);
  return 0;
}

This example seems to work quite ok when f is initialized by 1.0. But change this to 3.0 - and things start to get way more interesting pretty soon:

2.600000
2.500000
2.400001
...
0.000001

... leading to the infamous 'off-by-one' failure.


You think that you might be safe with >= instead of >? Think again:

float f = 5.0;
for(;f>=1;f-=0.4)
  printf("%f\n",f);

...
3.400000
3.000000
2.599999
2.199999
1.799999
1.399999

... and off-by-one we go again (as 0.99999 is less than 1).

like image 141
raina77ow Avatar answered Oct 21 '22 21:10

raina77ow