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

I wrote a small script to add values in a hash of arrays. Anyway, when numbers like "1483" was added to "-1483.00" I sometimes got an answer like "-9.09494701772928e-13". What?! I used printf to format the number to "-0.00". Why does perl do this? is there a way for me to make zero be "0"? Oh, this usually happened on the last iterations of additions. Thanks

Replies are listed 'Best First'.
Re: Why is Zero not 0?
by Joost (Canon) on Feb 01, 2008 at 23:18 UTC
    Binary floating point numbers are inexact. Or to be more precise: they're inexact for different values than decimal floating point numbers.

    For instance, 0.1 can't be represented exactly in an IEEE binary float (as used by the majority of CPUs that perl runs on). This means that you generally can't rely on any math operation involving floating point numbers to give you an exact result.

    Either use rational numbers (see Math::BigRat) or round the results (and note that many standard rounding strategies (like sprintf "%d" and sprintf "%0f") give results that don't conform to the "naive highschool" method of rounding - for more or less good reasons). See also Math::Round.

    update: note that "really integer" floats (perl uses doubles for floats) are exact within a very large range (a range larger than native integers on my machine at least), so xxxx.0 is generally exact. I suspect the numbers in your post aren't really the numbers used in the calculations.

    update 2: this is the standard text to bully people with

      You might want to read Why is Zero not 0?, especially as it references this article.

      You may want to store integer pennies rather than floating point dollars-and-cents.

      Please reap. This was intended for another thread.

Re: Why is Zero not 0?
by swampyankee (Parson) on Feb 02, 2008 at 01:35 UTC

    Read this article. Floating point numbers are only an approximation of rational, let alone real, numbers.

    Obviously, there are ways to make a number near zero be "0;" for example int.


    emc

    Information about American English usage here and here.

    Any Northeastern US area jobs? I'm currently unemployed.

Re: Why is Zero not 0?
by ikegami (Patriarch) on Feb 02, 2008 at 01:26 UTC
    $x = 0; $x += 0.1 for 1..10; $x_eq_1 = $x == 1 ? 'yes' : 'no'; print("$x = 1? $x_eq_1\n");
    1 = 1? no

    Some numbers can't be represented by floats. Your print statement is rounding the number. This include numbers that are periodic in binary. 0.1 is one of them.

    ... printf("\$x is really %.16e\n", $x);
    ... $x is really 9.9999999999999989e-001

    If you print your numbers using %.16e, you'll find at least one isn't what you think it is. You should never check floats for equality.

Re: Why is Zero not 0? (yuck)
by tye (Sage) on Feb 02, 2008 at 03:43 UTC

    Yeah, this is a pretty stupid feature. No, I'm not at all surprised that floating point isn't always precise. Yes, I find it quite stupid and very annoying to have almost half of my calculations that result in "zero" being displayed as "-0.00" due to trivia like single-bit errors that are impossible to avoid. This should just be fixed (yes, the fact that C got this wrong shouldn't prevent Perl from being better).

    printf displaying "0.02" means that the number I asked to have displayed is closer to "0.02" than it is to "0.01" or to "0.03"1. I don't need some special indicator displayed to tell me that the number might actually be less than "0.02" even though it is displayed as "0.02".

    1 Some of you might be thinking something like "or exactly halfway between". But if you are, then you are wrong because neither 0.015 nor 0.025 can be represented in (base-2) floating point.

    Now repeat the above paragraph (and footnote) with 0.02 subtracted from all of the example numbers. That logic still makes perfect sense. One would be a fool to see "0.00" and declare "This means that the number cannot be between -0.005 and 0.00; it must be a positive number!". Now, I could see having "%+.2f" display either "+0.00" or "-0.00" since at least "+0.00" could be considered misleading in the case of -0.000001. I could also see "%+.2f" displaying just "0.00" since zero isn't a positive number (and that'd be my preference, actually).

    Just a few days ago I was doing some calculations where I thought some totals given to me had had fees subtracted from them. So I wrote a quick Perl script to parse out the columns of numbers and do some quick multiplication and subtraction and display the results. I got:

    0.00 -0.00 -0.00 0.00 0.00 0.00 -0.00

    The fees hadn't been taken out. And that is just stupid output. Who would want to know that 3 of the calculations were ever so slightly inaccurate to one side and not care in the least that a bunch of the other calculation were ever so slightly inaccurate to the other side?!

    Entering the same data into Excel results in only "0.00" results. For those who can't believe that MicroSoft would ever do anything right, the same is true for Google spreadsheets. I couldn't find the spreadsheet app in my OpenOffice installation to verify it.

    (No, I don't actually expect sanity to be restored here. But I'm glad to have made the case.)

    - tye        

      Thank you! Thank You! Thank You! tye I could not have said it better myself. The focus of my post was not the fact that I didn't understand the output of printf necessarily but why would 4083 - 4083.0 = "-9.09494701772928e-13! My perl script was written in the same context as your script. For a quick and dirty report to show my users the analysis of an issue. Thank you all for your explanations. They were all good. I'll just mask everything with an int(). j
      use realreal;?
Re: Why is Zero not 0?
by dwm042 (Priest) on Feb 02, 2008 at 14:24 UTC
    There was a pretty interesting discussion of getting around the -0.00 issue at this node.
Re: Why is Zero not 0?
by runrig (Abbot) on Feb 01, 2008 at 23:19 UTC
    You apparently didn't use printf properly. What did you do? I missed the part about formatting to "-0.00" ...nevermind.
        I think that, so long as the number is less than zero && the number rounds to zero, then we get a leading "-0". Hence:
        C:\C>perl -e "printf \"%0.2f\", -0.0049" -0.00 C:\C>perl -e "printf \"%.0f\", -0.499" -0
        Cheers,
        Rob
Re: Why is Zero not 0?
by zentara (Cardinal) on Feb 03, 2008 at 18:45 UTC
    Why is Zero not 0?

    Just to stimulate some hypothetical B.S.'ing..... the "zero not being zero" problem is not just a programming problem. Math and Philosophy cannot find an exact zero either. All you can do is get closer to it, approaching from the positive or negative side. They use terms like "-0" or "0+" to signify approaching zero at infinite minuteness, from either the negative or positive side.

    Something to think about when you are high ( er... I mean meditating ;-) ).


    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
      Lol. Well, I believe that mathematically there is a zero just like there is a God.
        In integer math, there is an exact zero; but in the real world there isn't an exact anything..... only degrees of precision. When I was in engineering, 5 decimal places of accuracy was considered pretty good; but my space alien friends wouldn't touch anything with such sloppy tolerances. :-)

        I'm not really a human, but I play one on earth. Cogito ergo sum a bum