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

Hi monks,

i know perl is not aim at doing calculation at first, but here is a simple thing i coded, and the result is quite strange, could someone explain me why , and if there is a solution to avoid this, it would be welcomed !

I just add recursively 0.1 to a number, and sometime i got more than 1 decimal !

here is the code, following by the output :
#!/usr/bin/perl -w use strict; use warnings; my $bou = 20; my $beu = 0.1; my $nb=$bou/$beu; my(@bu); $bu[0]=0; for (my $i=1;$i<=2*$nb;$i++){ $bu[$i]=$bu[$i-1]+$beu; print "$i\t$bu[$i]\n"; }
and it gives :
1 0.1 2 0.2 3 0.3 4 0.4 5 0.5 6 0.6 7 0.7 8 0.8 9 0.9 10 1 11 1.1 ... 55 5.5 56 5.6 57 5.7 58 5.8 59 5.9 60 5.99999999999999 61 6.09999999999999 62 6.19999999999999 63 6.29999999999999 64 6.39999999999999 65 6.49999999999999 66 6.59999999999999 67 6.69999999999999 68 6.79999999999999 69 6.89999999999999 70 6.99999999999999 71 7.09999999999999 72 7.19999999999999 73 7.29999999999999 ... 98 9.79999999999998 99 9.89999999999998 100 9.99999999999998 101 10.1 102 10.2 103 10.3 104 10.4 105 10.5 ... 223 22.3 224 22.4 225 22.5 226 22.6000000000001 227 22.7000000000001 228 22.8000000000001 229 22.9000000000001 230 23.0000000000001 231 23.1000000000001 232 23.2000000000001 233 23.3000000000001 ... 396 39.6000000000003 397 39.7000000000003 398 39.8000000000003 399 39.9000000000003 400 40.0000000000003
Thanks, Marcel

Replies are listed 'Best First'.
Re: strange result for a simple addition ??
by choocroot (Friar) on Aug 25, 2006 at 20:14 UTC
Re: strange result for a simple addition ??
by roboticus (Chancellor) on Aug 25, 2006 at 19:03 UTC
    Marcel--

    Many floating point numbers don't have an exact binary floating point representation. So after a few operations, it's normal to get odd digits a few places to the right.

    For example, 1/3 doesn't have an exact decimal representation. If you truncate to 3 digits past the decimal, and subtract 1/3 three times from one, you'd also have an odd value:

    1.000 - 0.333 = 0.667 0.667 - 0.333 = 0.334 0.334 - 0.333 = 0.001

    --roboticus

      Actually 0.1 decimal can't be represented as a finite binary fraction so suffers from rounding errors and the accumulation of rounding errors that OP is seeing.


      DWIM is Perl's answer to Gödel
        Right...that's the situation I was giving an example of.

        --roboticus

Re: strange result for a simple addition ??
by rodion (Chaplain) on Aug 25, 2006 at 19:06 UTC
    Like other computer languages, the default for perl is to store floating point numbers in binary floating point. This doesn't exactly match up with decimal floating point. There is some round off error going back and fourth, and that's what you are seeing.

    You can

    • Round on display, using something like printf "%6.2f"
    • Use integer arithmetic, which doesn't have this problem. You can do your work in integers, then scale at the end.
    • Use a module which supports greater (or infinite) precision arithmatic
Re: strange result for a simple addition ??
by Not_a_Number (Prior) on Aug 25, 2006 at 19:27 UTC

    This question comes up regularly on Perlmonks. In fact, back when I was a novice Monkling, I actually asked (a variant of) it myself *blush* at (s)printf and rounding woes.

    It also, of course, regularly comes up on forums for other languages, since such phenomena are not restricted to perl.

    For the best explanation I have yet to find, please read this: Re: Re: Re: Bug? 1+1 != 2, by BrowserUK

Re: strange result for a simple addition ??
by swampyankee (Parson) on Aug 25, 2006 at 19:52 UTC

    Floating point numbers are a subset of rational numbers. Just like 1/3 cannot be exactly represented by a finite decimal number (0.33333.....), as it cannot be represented by a finite expansion of powers of ten, numbers that can't be represented as a finite sum of powers of two cannot be represented as floating point numbers. There are quite a few programmers (see na-net) who have to deal with this all the time, as when trying to solve a 100000 DOF finite element model. Most perlists don't have to do such things (that sort of programming is still largely done in Fortran, although C++ is becoming more prevalent). In other words, it's expected behavior unless you're using a package like Macsyma or Maple.

    See, for example, "What Every Programmer Should Know about Floating Point" by David Goldberg.

    emc

    Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.

    Albert Einstein
Re: strange result for a simple addition ??
by radiantmatrix (Parson) on Aug 25, 2006 at 20:04 UTC

    That's what Math::BigFloat is for. See, as explained above, many languages only support a certain level of precision natively for storing floating numbers. If you need precision for floating-point math, the module above is your friend.

    <radiant.matrix>
    A collection of thoughts and links from the minds of geeks
    The Code that can be seen is not the true Code
    I haven't found a problem yet that can't be solved by a well-placed trebuchet
Re: strange result for a simple addition ??
by ikegami (Patriarch) on Aug 25, 2006 at 19:39 UTC
    If possible, the best solution is to calculate your decimal numbers from integer numbers and not from other decimal numbers. This prevents an accumulation of error. If you case, this is possible.
    $bu[0] = 0; for my $i (1 .. 2*$nb) { # Easier to read. Just as efficient. $bu[$i] = $i * $beu; # Fix. print "$i\t$bu[$i]\n"; }