in reply to Help me make a test case for Math::BigFloat

I don't think this is a bug, just an artifact of the transition between IEEE float constants and bignum objects:

c:\>perl -MMath::BigFloat -wle"print Math::BigFloat->new(1) - Math::BigFloat->new( .999999999999 +999 )" 0.000000000000001 c:\>perl -MMath::BigFloat -wle"print Math::BigFloat->new(1) - Math::BigFloat->new( .999999999999 +9999 )" 0 c:\>perl -MMath::BigFloat -wle"print Math::BigFloat->new(1) - Math::BigFloat->new('.999999999999 +9999')" 0.0000000000000001 c:\>perl -MMath::BigFloat -wle"print Math::BigFloat->new(1) - Math::BigFloat->new('.999999999999 +99999999999')" 0.00000000000000000000001

Notice how once you get beyond ~16 decimal places in the constant, the result is wrong. However, if you pass the constant as a string rather than allowing Perl to convert it to a IEEE float before passing it to bignum, the accuracy is retained.

So the answer is to use string constants to initialise your bignum objects.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Replies are listed 'Best First'.
Re^2: Help me make a test case for Math::BigFloat
by fizbin (Chaplain) on Mar 07, 2006 at 02:37 UTC

    I don't care what I'm initializing something with, there shouldn't be any way to create $ev such that both $ev and 1-$ev print as "1".

    And as for initializing everything as strings, look at this code:

    #!perl use Math::BigFloat; print ((new Math::BigFloat("1")) - exp(new Math::BigFloat("-7") / (new Math::BigFloat("10")**(new Math::BigFloat("17"))))); # Properly prints "0" # (well, something like 7e-17 would be closer, but I'll accept 0)
    Compare it to this code, which is the same but with a use bignum:
    #!perl use bignum; use Math::BigFloat; print ((new Math::BigFloat("1")) - exp(new Math::BigFloat("-7") / (new Math::BigFloat("10")**(new Math::BigFloat("17"))))); # Incorrectly prints "1"
    It would appear then that we have a bug not so much in Math::BigFloat directly, but somewhere in the intersection of Math::BigFloat, bignum, and the magic bignum sprinkles on exp.
    --
    @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/

      Hmm. There seem to be two interacting problems here.

      1. exp doesn't appear to be overloaded by either bignum or Math::BigFloat?
        #!perl -slw use strict; use overload; #use bignum; use Math::BigFloat; printf "exp(-7e-17): %.17f\n", my $exp = exp( Math::BigFloat->new( '-7 +e-17' ) ); eval{ print overload::Overloaded( $exp ) } or warn $@; print overload::StrVal( $exp ); printf "1-exp(-7-e17): %.17f\n", Math::BigFloat->new("1") - $exp; __END__ C:\test>junk7 exp(-7e-17): 0.99999999999999989 Can't call method "can" without a package or object reference at c:/Pe +rl/lib/overload.pm line 54. 1 1-exp(-7-e17): 0.00000000000000000
      2. And with bignum enabled, Math::BigFloat seems to forget how to do math? At least if the math involves one BigMath object and one normal perl number.
        #!perl -slw use strict; use overload; use bignum; use Math::BigFloat; printf "exp(-7e-17): %.17f\n", my $exp = exp( Math::BigFloat->new( '-7 +e-17' ) ); eval{ print overload::Overloaded( $exp ) } or warn $@; print overload::StrVal( $exp ); printf "1-exp(-7-e17): %.17f\n", Math::BigFloat->new("1") - $exp; __END__ C:\test>junk7 exp(-7e-17): 0.99999999999999989 Can't call method "can" without a package or object reference at c:/Pe +rl/lib/overload.pm line 54. 1 1-exp(-7-e17): 1.00000000000000000

      All of which makes me glad that I rarely need the accuracy beyond 53-bits and when I do, 64-bit ints suffice.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        All of which makes me glad that I rarely need the accuracy beyond 53-bits and when I do, 64-bit ints suffice.

        This is why I prefer to keep things as rationals (or bigrats), rather than floats - it's possible to represent them accurately without encountering the inevitable rounding or truncating errors. True, all the irrational numbers will still truncate, but the rationals won't. I only use the decimal representation for display purposes, sometimes.