Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Floating Point Looping In Perl

by kiruthika.bkite (Scribe)
on Aug 13, 2010 at 04:33 UTC ( #854821=perlquestion: print w/replies, xml ) Need Help??
kiruthika.bkite has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,
I have used floating point looping in the following code.
for ($i=1.1;$i<=1.6;$i+=.1) { print "$i\n"; }
I have expected that it will give the output from 1.1 to 1.6 but it gave the following output.

Why it is not printing 1.6.Please explain me.
Thanks in advance.

Replies are listed 'Best First'.
Re: Floating Point Looping In Perl
by ikegami (Pope) on Aug 13, 2010 at 04:42 UTC

    Both 1/10 and 16/10 are periodic numbers in binary, just like 1/3 is in decimal. It would take an infinite amount of memory to store 0.1 and 1.6 as floats. Some rounding error occurs.

    $ perl -e' printf "%.20f\n", 1.6;' 1.60000000000000008882
    And to see what's happening for you:
    $ perl -e' for ($i=1.1;$i<=1.6;$i+=.1) { printf "%.20f\n", $i; } printf "\n%.20f\n", $i; ' 1.10000000000000008882 1.20000000000000017764 1.30000000000000026645 1.40000000000000035527 1.50000000000000044409 1.60000000000000053291

    One solution is to use integers for the counter, and generate the floats from them

    $ perl -le'for my $i (1..6) { print 1+$i/10 }' 1.1 1.2 1.3 1.4 1.5 1.6

    It gives precise checks for the loop, and there's no accumulation of error for the result.

Re: Floating Point Looping In Perl
by Anonymous Monk on Aug 13, 2010 at 04:40 UTC
Re: Floating Point Looping In Perl
by aquarium (Curate) on Aug 13, 2010 at 06:25 UTC
    A good habit to get into (i think) is not to use equality operator at all for numerical condition testing, especially so for floating point numbers. instead test for $i<1.7
    only use equality sparingly in conditionals altogether, and program defensively. Perl is not a strongly typed language, which gives flexibility, but you do need to be a bit careful sometimes. And floating point math is what it is, an approximation of decimal numbers.
    the hardest line to type correctly is: stty erase ^H
      The recommendation from my numerical analysis course was to use a "delta" value when comparing, depending on "how close" the values needed to be for you to decide they were equal.

      Something like

      while ($i - $j < $delta) { ... }
      The trick is selecting a delta that works. For instance if $i was 2E40 and $j was 1E40, selecting a delta of 1E-40 probably wouldn't work - it's going to depend on how many significant figures your platform's floating point numbers can represent (the example above would require 80 significant figures, if I'm remembering all this right: 40 in front of the decimal point and 40 after it). You should carefully check out your platform's floating point representation and precision before embarking on adventures in floating point computations.

      This is why many financial calculations in which it was necessary to be precise about exact cents used to be (and probably are still) done in cents rather than in fractional dollars - you can precisely add and subtract integers as long as you have enough digits to represent the amounts you care about.

        Most accounting and telecommunications charging tables that I've worked with were to the fourth decimal place. This wasn't in perl but same applied, we ended up using a math library which used BCD or similar, which produces much better results and rounding functions than floating point. But that's probably beside the point. You can also create an "artificial" loop variable that counts in integers instead of decimals..since you know the number of steps.
        the hardest line to type correctly is: stty erase ^H
      That will only help if the rounding error make the number slightly larger. It doesn't help if the rounding error makes the number slightly smaller, and that does happen. It's not a good solution.
Re: Floating Point Looping In Perl
by JavaFan (Canon) on Aug 13, 2010 at 09:30 UTC
    There's a manual that explains it. It's called perlnumber.

      That would be perlnumber or perldoc perlnumber, in case you don't know where to find it.

Re: Floating Point Looping In Perl
by shevek (Beadle) on Aug 13, 2010 at 17:47 UTC
    Comparing floating point numbers is not precise unless you make it so by writing your own equal subroutine or treat the data as integers and convert to floating point on display. Floating point numbers are represented internally as binary. There are certain floating point numbers that cannot be represented exactly in binary on your computer. This is similar to 2/3 not being exactly represented in decimal.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://854821]
Approved by ikegami
Front-paged by MidLifeXis
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (5)
As of 2018-06-18 04:20 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (107 votes). Check out past polls.