15

I had an exam today in C and I was asked a question similar to:

What is wrong with this program:

for( x = .1 ; x != 1.0 ; x += .1)
    printf("%f\n", x);

I couldn't solve it and since I had to write something I marked .1 as an error. But, when I went back home, I run this program, It turned out that it doesn't break when x equals to 1.0 and stuck in an infinite loop:

$ cat exam.c
#include <stdio.h>

int main(int argc, char **argv)
{
    float x;

    for(x = .1 ; x != 1.0 ; x += .1)
        printf("%f\n", x);

    return 0;
}
$ gcc exam.c -o exam
$ ./exam
0.100000
0.200000
0.300000
0.400000
0.500000
0.600000
0.700000
0.800000
0.900000
1.000000 <- ?
1.100000
1.200000
1.300000
1.400000
1.500000
....

Could someone please explain why this is happening.

Jarrod Dixon
  • 15,727
  • 9
  • 60
  • 72
  • 12
    [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Alok Save Nov 24 '12 at 14:39
  • 1
    Welcome to the awesome world of floating-point math. – CAFxX Nov 24 '12 at 14:40
  • 1.00000 may actually be something like 1.000000001. The nature of floating points. – Inisheer Nov 24 '12 at 14:40
  • 1
    Besides that, you should never terminate an incrementing for loop with a test for equality -- always "equal or greater" or some such. – Hot Licks Nov 24 '12 at 14:41
  • 1
    @BoPersson: while in *this* case the answer *may* be the same, redirecting a C question to a Python one is IMHO a mistake - especially considering the fact that Python does not use fixed FP types, such as the ones defined in IEEE-754, contrary to most C implementations. – thkala Nov 24 '12 at 17:51
  • @Als: I find that [floating-point-gui.de](http://floating-point-gui.de) is a much better link to point newbies to. – Daniel Pryden Nov 25 '12 at 00:14

6 Answers6

18

<= or < is not the solution!

Using of floating points in the loop is not without issues. The rounding error accumulates. Even with <=, the loop might not run the right number of times.

It works for <=1.0 (10 times), but runs one time less than expected for <=50.0 (499 times).

 for(i = 0.1 ; i <= 50.0 ; i += 0.1)
       { ... }//runs 499 times, not 500!

This is an issue that might not be very easy to discover, if you do run into it. Rounding it before comparison (rounding functions) might help, but the only sure-shot solution is to...

Use integers as control variables in loops.

Community
  • 1
  • 1
Anirudh Ramanathan
  • 46,179
  • 22
  • 132
  • 191
17

This is a typical question for homework.

The Problem is that the 0.1 cannot be exactly stored in a float better check for <= 1.0

However this just works only for a very limited range like Cthulhu said. I missed that problem completely. Of cause it is better to use int and divide its value later.

rekire
  • 47,260
  • 30
  • 167
  • 264
  • +1. I did not know about this trick, but I've always used <= for everything. – Victor Zakharov Nov 24 '12 at 14:40
  • 1
    @Cthulhu you are right, I added a line pointing to your answer. For this special question my solution would work, but of cause not until that 500 example. You got a +1 from me too. – rekire Nov 24 '12 at 18:24
3

never use != in the for loop, it leads to a very difficult to find errors when your loop variable never reaches the value you expect. always use < instead.

lenik
  • 23,228
  • 4
  • 34
  • 43
2

It is due to IEEE floating point standard. Check Wikipedia

0.1 + 0.2 = 0.3 => FALSE - Expected: 0.3 | Real: 0.30000000000000004

Check out real (JavaScript) demo here: http://k8.no-ip.org/stackoverflow/13542220.htm

SmartK8
  • 2,616
  • 1
  • 29
  • 37
1

0.1 cannot be stored exactly in a float. Floating point numbers contain an approximate value and you are trying to equalize it to an exact value.

Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
  • 4
    @rekire: And so have hundreds of answers to the dozens of duplicates for this Q, so whats your point? – Alok Save Nov 24 '12 at 14:42
1

Suggestion, every time you need loops use integers.

int x;
float y = 0;
for( x = 1; x < 11; x += 1){
    y += 0.1; 
    printf("%f\n", y);
}

Alternatively you can use this too:

for( x = 1; x < 11; x += 1){
    printf("%f\n", ( x / 10.0 ) );
}

In both cases you keep the loops values as integers.

Alberto Bonsanto
  • 17,556
  • 10
  • 64
  • 93