Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Clean log_10 ?

by LanX (Saint)
on Nov 28, 2019 at 16:26 UTC ( [id://11109375]=perlquestion: print w/replies, xml ) Need Help??

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

Hi

I got bitten by the fact that log is producing a float

by definition (see log )

sub log10 { my $n = shift; return log($n)/log(10); }

but

DB<36> $num = 1e12 DB<37> $log10 = log($num)/log(10) DB<38> p $log10 12 # Looks good, right? DB<39> p $log10 % 3 2 # surprise! DB<40> p int($log10) 11 # Oh one of Perl's DWIM show Float as +Integer DB<41>

instead of resorting to tricks like secretly rounding up the hidden float, is there a recommended library?

Probably POSIX something?

update

clarification, I'm interested to get the log10 of a whole number.

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Replies are listed 'Best First'.
Re: Clean log_10 ?
by pryrt (Abbot) on Nov 28, 2019 at 16:53 UTC
    C:\Users\Peter>perl -MPOSIX=log10 -le "$,=', ';print $_, int($_) for l +og(1e12)/log(10), log10(1e12)" 12, 11 12, 12

    log() is implemented as precisely as possible for base e; unfortunately, dividing one log-base-e by another is not always as precise as you want; OTOH, using POSIX::log10, you get the function implemented as precisely as possible for base 10, which appears to be what you want.

      Thanks I went directly to POSIX#MATH and only saw constants and missed the function log10.

      This seems to work reasonably well up to 1e308! :)

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Clean log_10 ?
by Eily (Monsignor) on Nov 28, 2019 at 16:57 UTC

    I'm interested to get the log10 of a whole number
    (IIRC) Unless that number is a power of ten, the log10 is going to be irrational. This mean you wouldn't even be able to get an exact value by using Rationals (that's the definition). Best you can do to have an "exact value" would be something like:
    sub log10 { sprintf("%e", $_[0]); print "log10($_[0]) = $2 + log10($1)" }
    where you can drop the right side of the addition when $1 == 1.0. Oh and the right side is guaranteed to be in [0;1)

    Edit: I suppose POSIX's log10, as demonstrated by pryrt does give the correct answer for the special cases that are powers of ten. But it's still going to give an approximation for all other numbers.

      > > I'm interested to get the log10 of a whole number

      > the log10 is going to be irrational

      Yeah you're right.

      Rewording: I need the correct int(log10) to reproduce the E notation of a whole number.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        Do you mean that the number you are taking the log of will always be a power of 10? In which case, the log will be almost an integer, so round to nearest int: $power = int($log10 + 0.5);

        Otherwise, why not use sprintf "%e", $num or similar?

        Dave.

Re: Clean log_10 ?
by davido (Cardinal) on Nov 28, 2019 at 18:22 UTC

    Math::BigInt:

    sub blog10 { my $bn = shift; require Math::BigInt; return (ref($bn) ? $bn->copy : Math::BigInt->new($bn))->blog(10); } my $bn = 1e12; my $blog10 = blog10($bn); print "blog10($bn): $blog10\n"; print "mod($blog10,3): ", $blog10 % 3, "\n"; print "int($blog10): ", int($blog10), "\n";

    The output:

    blog10(1000000000000): 12 mod(12,3): 0 int(12): 12

    ...which should be what you expect it to be.

    This does silently upgrade your number to a Math::BigInt object. Calling ref($blog10) would return Math::BigInt, for example. If that's objectionable, modify your blog10 function as follows:

    return (ref($bn) ? $bn->copy : Math::BigInt->new($bn))->blog(10)->numi +fy;

    You could make this even more "black box" by auto-decorating and auto-undecorating based on logic:

    sub blog10 { my $n = shift; my $bn = ref($n) ? $n->copy : do { require Math::BigInt; Math::BigInt->new($n) }; my $ret = $bn->blog(10); return ref($n) ? $ret : $ret->numify; }

    Dave

Re: Clean log_10 ?
by haj (Vicar) on Nov 28, 2019 at 19:10 UTC
    SCNR: sub log10 { 0 + (sprintf("%e", shift) =~ /e([+-]?\d+)/)[0] }

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-03-29 15:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found