Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re: Numeric Comparisons Randomly Giving the Wrong Result

by halfcountplus (Hermit)
on Sep 30, 2010 at 12:06 UTC ( [id://862783]=note: print w/replies, xml ) Need Help??


in reply to Numeric Comparisons Randomly Giving the Wrong Result

Here's an important fact about "floating point" numbers as stored in a computer: they are not true decimal numbers, because computers can only store binary values. That means floats can only accurately represent a number that is an inverse power of two, eg, 1/2, 1/4, 1/8, 1/16 and so on. Notice that does not include 1/10, aka 0.1. You can observe this on your system using perl:

for (my $i = 0; $i<30; $i += 0.1) { print "$i "; }

If you run that, you will notice frequently the numbers ARE NOT an even multiple of 0.1, eg, with 32 bit floats you get "5.9 5.99999999999999 6.09999999999999 6.19999999999999" "22.5 22.6000000000001 22.7000000000001 22.8000000000001", etc. In fact, they are NEVER an even multiple of 0.1, but this is not always clear since there is also a limit to the number of "decimal" places when the number is rendered in non-binary form.

This is not just a perl issue, and there are notorious legends of accounting software disasters because of it; it's why when you are programming applications involving dollars and cents and division, always:

use integer;

Then use cents, not dollars, and remember, this is rounded down -- if you want to include fractions of a cent, decide how many decimal places you need and use that fraction as a base unit. Money is not a floating point measure. It is of fixed precision.

Replies are listed 'Best First'.
Re^2: Numeric Comparisons Randomly Giving the Wrong Result
by mjscott2702 (Pilgrim) on Sep 30, 2010 at 13:40 UTC
    Is using the integer pragma such a good idea? From the documentation:
    1. use integer; 2. $x = 10/3; 3. # $x is now 3, not 3.33333333333333333

    If only addition and subtraction are being used, should be fine - if other arithmetic operations are happening, wouldn't that result in a loss of precision?

      Only if your units are not whole, indivisable units already. If you do all your calculations in cents and do not allow sub-cent amounts, then you won't need to care about rounding.

      If you do fancy calculations, like repeatedly adding fractional parts of things, you need to give deep thought to all your calculations anyway, whether they are in floating point or integer numbers.

        What about this situation - assuming you can get a large loan in Galactic Credits, at 0% APR, for a year:
        use strict; use warnings; use diagnostics; my $amount = 1e9; my $months = 12; my $repayment = $amount/$months; print "Monthly repayment = $repayment\n"; use integer; $repayment = $amount/$months; print "Monthly repayment = $repayment\n";

        prints out:

        Monthly repayment = 83333333.3333333
        Monthly repayment = 83333333
        

        which is not the same thing!

        On a different, but related note, increasing the loan to 1e12 Galactic Credits, gives this:

        Monthly repayment = 83333333333.3333
        Monthly repayment = 0
        

        That's because the loan amount is too big to hold in an integer (on my machine anyway):

        perl -le'use POSIX;print for SHRT_MAX, INT_MAX, LONG_MAX, FLT_MAX, DBL +_MAX;' 32767 2147483647 2147483647 3.40282346638529e+38 1.79769313486232e+308

        So use the integer pragma with caution!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://862783]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2024-04-24 06:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found