Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Why do these produce different values?

by mr.nick (Chaplain)
on Jan 25, 2006 at 19:50 UTC ( [id://525551] : perlquestion . print w/replies, xml ) Need Help??

mr.nick has asked for the wisdom of the Perl Monks concerning the following question:

Greetings from an old Monk, Can someone explain to me why the following code snippet produces the following?
-output- 46 45
-code snippet- $foo= 44123.2000 / 959.2; print "$foo\n"; print int($foo),"\n";
Thanks as this has been driving me crazy! (And I have this horrible feeling I'm doing something crazy-stupid :) (btw, perl 5.005_03 on Solaris)

mr.nick ...

Replies are listed 'Best First'.
Re: Why do these produce different values?
by ikegami (Patriarch) on Jan 25, 2006 at 20:20 UTC
    perl -e "printf '%.20f', 44123.2 / 959.2; 45.99999999999999300000

    Numbers have 52 bits of precision. print round off a few of the least significant of the 52 bits. In this case, this causes 45.999999999999993 to display as 46.

    int, on the other hand, truncates 45.999999999999993 to 45.

    So why is the answer 45.999999999999993 and not 46? That's because 44123.2 and/or 959.2 is a periodic number in binary, or one of the intermidiary numbers in the conversion from string to number is a periodic number in binary. Others and searches will provide more info on this.

Re: Why do these produce different values?
by Roy Johnson (Monsignor) on Jan 25, 2006 at 20:07 UTC
Re: Why do these produce different values?
by davido (Cardinal) on Jan 25, 2006 at 21:11 UTC

    Observe the output of the following code:

    printf "%2.15f", 44123.200/959.2;

    The output, due to rounding errors inherent in any system where base 10 floating point numbers are converted to base 2 for arithmetic work, and then converted back to base 10 for display, is "45.999999999999993".

    Unless you tell it to do otherwise (as I have done with printf, Perl, like most languages rounds that to 46 for display purposes (I can't remember the number of decimal digits Perl will display before rounding). But int does something entirely different from rounding; it simply drops everything after the decimal point. So 45.9999999999999993 gets truncated by int to 45, while printing 45.99999999999993 gets rounded up to 46.

    I first encountered this fact of life back in my first high school Computer Science course in 1983 or so, taught on Apple II+ computers with some sort of Apple floating point BASIC. But it existed long before 1983, and will continue to exist as long as we use a finite number of base-2 digits to internally represent (and perform operations on) floating point base-10 numbers.


Re: Why do these produce different values?
by Aristotle (Chancellor) on Jan 25, 2006 at 20:34 UTC

    See Floating-Point Basics, which explains the issues about doing math on computers in detail.

    Makeshifts last the longest.

Re: Why do these produce different values?
by GrandFather (Saint) on Jan 26, 2006 at 03:19 UTC

    Others have answered the basic question well. The fundemental issue is that finite resolution binary fractions can not exactly represent decimal fractions so you always get rounding or truncation issues when using decimal fractions.

    DWIM is Perl's answer to Gödel