Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

exp() bignum issue

by cormanaz (Deacon)
on Aug 30, 2020 at 19:52 UTC ( [id://11121203]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings fellow monks. I hope you are all surviving the Apocalypse ok.

I am trying to apply a logistic regression equation to classify some new cases. The equation yields rather large numbers for the z value. When I try to convert one of these values to a probability like so (simplified example):

my $z = -15863.8668285308; my $e = exp($z * -1); my $prob = 1/$e;
$e winds up with value 1.#INF. I researched this and found that it is a problem with how perl handles large numbers.

So I added use bignum;. This stores $z as type Math::BigFloat, but when I try to get the exp() result, it doesn't return. It's not hanging because I can see from Windows task manager that the interpreter is running, but after minutes it is has still not returned. The calculator on my Windows machine returns the answer in a fraction of a second, so something is clearly not right. What am I doing wrong?

Replies are listed 'Best First'.
Re: exp() bignum issue
by Fletch (Bishop) on Aug 30, 2020 at 20:40 UTC

    Make sure you give it a while to run. It hangs for over three minutes just computing $e for me on OS X (Mac Pro late 2013 sitting otherwise idle) but does eventually produce an answer. These are hyoooooge numbers (checking with Wolfram Alpha which shows they're on the order of 10**6889) and I'm going to guess that it's just CPU bound.

    $ time perl -MLog::Log4perl=:easy -Mbignum -E 'Log::Log4perl->easy_ini +t($DEBUG);$|=1;INFO(qq{before});my $z = -15863.8668285308; INFO(qq{z: + }, $z); my $e = exp( $z * -1 ); INFO(qq{e: }, $e); my $p = 1.0/$e;IN +FO(qq{p: }, $p);INFO(qq{DONE});' 2020/08/30 16:29:11 before 2020/08/30 16:29:11 z: -15863.8668285308 2020/08/30 16:32:45 e: 38888865970354639568651511148772888670670000000 +000000000000000000000000000000[boatload o 0s] 2020/08/30 16:32:45 p: 0.0[boatload o 0s]00025714300868590761106006809 +94899649646402 2020/08/30 16:32:45 DONE perl -MLog::Log4perl=:easy -Mbignum -E 214.12s user 0.15s system 99% + cpu 3:34.33 total

    Edit: added missing phrase

    Update: If you install a faster math library, e.g. Math::BigInt::GMP and make sure that's used (add a line use Math::BigFloat lib => q{GMP};), then this returns immediately. The problem is most likely the default pure Perl bignum implementation Math::BigInt::Calc.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      This problem is solved, not because I got the function to run more quickly but because I was getting that huge number because of a mistake in my regression equation. :-/

      It's still true, however, that Windows calculator does e ^ 15863.8668285308 in the blink of an eye. I wonder why it's so much faster...

        ... Windows calculator does e ^ 15863.8668285308 in the blink of an eye. I wonder why it's so much faster

        It's so much faster because it uses an executable that was built from optimized C (and perhaps also assembly) routines.
        The pure perl Math::BigFloat can't compete with that.

        <plug> In perl, use Math::MPFR in order to get the same (perhaps even better) performance compared to the Windows calculator. </plug>
        # 53 bit precision, rounding to nearest C:\>perl -MMath::MPFR -le "print exp(Math::MPFR->new('15863.8668285308 +'))" 3.8888865970333893e6889 # 64 bit precision, rounding to nearest C:\>perl -MMath::MPFR=":mpfr" -le "Rmpfr_set_default_prec(64);print ex +p(Math::MPFR->new('15863.8668285308'))" 3.88888659703546523928e6889 # 113 bit precision, rounding to nearest C:\>perl -MMath::MPFR=":mpfr" -le "Rmpfr_set_default_prec(113);print e +xp(Math::MPFR->new('15863.8668285308'))" 3.88888659703546395686515111487812115e6889
        You can, of course, additionally do the inversion in one step:
        C:\>perl -MMath::MPFR -le "print 1 / exp(Math::MPFR->new('15863.866828 +5308'))" 2.5714300868604479e-6890
        NOTE: Math::MPFR requires both the gmp and mpfr libraries.
        You could also do the same arithmetic (without the fine grained control over precision) using Math::GMPf - which requires the gmp library only.
        However, the gmp project recommends mpfr over the floating point gmp routines.

        Cheers,
        Rob
Re: exp() bignum issue
by salva (Canon) on Aug 31, 2020 at 13:11 UTC
    What is your problem exactly, because Perl can usually handle this cases correctly.

    At least, the following code works for me:

    sub expit { my $x = shift; 1.0/(1.0 + exp(-$x)); }

    Or do you really want to manage probabilities that are under the 1e-308 threshold, and that's why you need Math::BigFloat?

Re: exp() bignum issue
by swl (Parson) on Aug 31, 2020 at 03:29 UTC

    The issue has been solved so this is just a data point, but it's also worth looking at Math::AnyNum. It loads MPFR and GMP without you needing to tell it to.

Re: exp() bignum issue
by jo37 (Deacon) on Aug 30, 2020 at 21:10 UTC

    Have some patience. Even

    echo 'e(15863)' | bc -l
    will take some time to complete.

    Greetings,
    -jo

    $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11121203]
Approved by LanX
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (3)
As of 2024-03-29 01:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found