RobertCraven has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks, is it possible to use float in a for loop?
I tried this:
#!/usr/bin/perl use warnings; use strict; for (my $i = 0 ; $i < 9 ; $i += 0.1){ print "$i\n"; } OUTPUT (truncated): (...) 4.9 5 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.99999999999999 6.09999999999999 6.19999999999999 6.29999999999999 6.39999999999999 6.49999999999999 (...)
Depending on the initial value of $i, it adds 0.09 at a different point.
Many thanks for all answers!

Replies are listed 'Best First'.
Re: for loop with float
by ikegami (Patriarch) on Jul 24, 2008 at 22:35 UTC

    The computer cannot accurately store 1/10 since it's a periodic number in binary (just like 1/3 is periodic in decimal).

    >perl -e"printf '%.16e', 0.1" 1.0000000000000001e-001 ^ | |

    Avoid the accumulation of error:

    for (0..89) { my $i = $_ / 10; print "$i\n"; }

    Update: and/or round your results.

Re: for loop with float
by FunkyMonk (Bishop) on Jul 24, 2008 at 22:46 UTC
    it adds 0.09 at a different point
    Not quite, it adds 0.099999999. That's just the sort of thing you should expect with floating point numbers in any language. See Floating point accuracy problems on Wikipedia

    Unless I state otherwise, all my code runs with strict and warnings
Re: for loop with float
by BrowserUk (Patriarch) on Jul 24, 2008 at 22:47 UTC
      Thank you all very much for the insight!
Re: for loop with float
by gloryhack (Deacon) on Jul 24, 2008 at 22:47 UTC
    Answering the question as asked, the answer is yes:
    #!/usr/bin/perl use warnings; use strict; for (my $i = 0 ; $i < 9 ; $i = sprintf("%.1f", $i + 0.1)) { print "$i\n"; }

    Although ikegami's answer is probably what you want.

Re: for loop with float
by swampyankee (Parson) on Jul 25, 2008 at 04:09 UTC

    Obviously, it's possible to use floats as increments in for loops: you're doing it. It's just a bad idea, at least partly because accumulation of errors means that the number of loop iterations cannot be guaranteed to be identical across platforms (or even across two versions of Perl built with different compiler options on the same machine).

    As mentioned by prior posters, 0.1 cannot be exactly represented in floating point, as 0.1 cannot be exactly represented as a finite sum of the powers of 2, in the same way that 1/3 cannot be exactly represented as a finite sum of powers of 10. For this reason, x = 5 + 0.1 will look like 5.0999999, because 5.1 can't be exactly represented. Floating point numbers are not real numbers; they are only approximations to real numbers, and that only within a finite range. This article will make this point much clearly than I.


    Information about American English usage here and here. Floating point issues? Please read this before posting. — emc

Re: for loop with float
by jethro (Monsignor) on Jul 24, 2008 at 23:24 UTC
    Whenever I use fractional numbers in my programs, I always use rounding before printing them. For example:
    $i= int($i*100+.5)/100;
    This makes sure you get exactly two numbers after the point. If I don't want to round the number I still add a small fractional number instead of 0.5, so that I don't get 5.99 if it really should be 6.00

        Because I would do anything to avoid printf. I've written a rounding sub in half the time I need to read the printf man page. For me printf is symbolizing the awkwardness of C programming I'm happy to have left behind

        But thanks for the TMTOWTDI ;-)