Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

log() and int() problem

by Anonymous Monk
on Dec 25, 2012 at 16:47 UTC ( #1010275=perlquestion: print w/replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to write a program to check if a number is a power of 5, but I came across a weird problem. Bellow is a code which illustrates my issue:
my $x = 125; my $l = log($x) / log(5); print "LOG == $l\n"; print "int(LOG) == ", int($l), "\n"; print "Are equal: ", ($l == int($l)) ? "true\n" : "false\n";
It prints:
LOG == 3 int(LOG) == 3 Are equal: false
For $x = 25 it works as expected, but for  $x = 125 (and probably other numbers), it acts really weird. It says that 3 != int(3). I'm wondering how is this possible... Is there some explanation for this?

Thank you

Replies are listed 'Best First'.
Re: log() and int() problem
by moritz (Cardinal) on Dec 25, 2012 at 17:02 UTC
      Idly curious why a loop and "/=" are needed. Not questioning but curious. Example?
        Add  print "$num\n"; and you can see how the loop works
Re: log() and int() problem
by toolic (Bishop) on Dec 25, 2012 at 17:02 UTC
Re: log() and int() problem
by LanX (Bishop) on Dec 25, 2012 at 17:17 UTC
    when using Data::Dumper you will see that $l is seen as a string not an integer

    print "LOG      == ",$l,Dumper \$l,"\n";


    LOG      == 3$VAR1 = \'3';

    As others pointed out log only returns floats up to certain precision, which IIRC also depends on the current implementation of Perl (that is compiling options). And internally floats are stored in the string-slot of a variable.

    That means the slight calculation error might be too small to be shown by a print but is still sufficient to let == fail. Even if print would show the discrepancy, your approach wouldn't always work.

    So better go the other way round and check if 125 == 5**$x with $x=int($l+$tolerance)

    EDIT: The approach Moritz updated into his post is even better.

    Cheers Rolf

      And internally floats are stored in the string-slot of a variable
      No they're not. An xpvnv has separate slots for an int, a float and a string:
      [davem@pigeon bleed]$ p -MDevel::Peek -e'$x=1; $x=2.2; $x = "three"; D +ump $x' SV = PVNV(0x1ae3150) at 0x1b021d0 REFCNT = 1 FLAGS = (POK,pPOK) IV = 1 NV = 2.2 PV = 0x1afb360 "three"\0 CUR = 5 LEN = 16


        OK, thanks for correcting!

        (I already suspected that I should place one more "IIRC". :)

        Maybe I remembered something different or Scalar::Util::dualvar confused me or the reality in perl is even more complex. (and the latter wouldn't surprise me)

        Cheers Rolf

        PS: or was it JS ... ?!?


        For the records, here the source of my misunderstanding

        from perlnumber:

        Perl can internally represent numbers in 3 different ways: as native integers, as native floating point numbers, and as decimal strings. Decimal strings may have an exponential notation part, as in "12.34e-56" . Native here means "a format supported by the C compiler which was used to build perl".

        emphasis added.

      Thank you very much. I solved my issue with adding and subtracting 1 from the returned value.
      I think that perl should do this internally.
      my $l = log(125) / log(5); $l += 1; $l -= 1; print $l == int($l);

      Thank you all for the great answers.

        I solved my issue with adding and subtracting 1 from the returned value
        Sorry, but that's a terrible "solution". Your example floating point inaccuracy happens to be slightly greater than three. Since the int function truncates, consider what happens if the inaccuracy happens to be slightly less than three. Though a crude fix would be to add 0.5 (i.e. int($l+0.5) instead of int($l)), the perl documentation advises against using int for rounding and suggests sprintf and the POSIX floor and ceil functions as sounder alternatives.

        Still don't understand why you don't go with moritz's solution.

        > I solved my issue

        you're very optimistic.

        I delved into Devel::Peek and I'm still not sure which type casting or crossed thresholds produced different results for 2 and 3.

        Anyway you're voyaging dangerous grounds, don't be surprised if your Float to Int conversions breaks again.

        Better rely on on already shown pure integer arithmetic for your integer (sic) tests. (rule of thumb!)

        Cheers Rolf


        lanx@nc10-ubuntu:~$ perl -MDevel::Peek -e'$|=1;$e=2;$x=log(5**$e)/log( +5); Dump $x; print ("\n", ($x==$e) ? "" : "not " ,"equal\n\n"); Dump + $x;' SV = NV(0x9c86840) at 0x9c70f68 REFCNT = 1 FLAGS = (NOK,pNOK) NV = 2 equal SV = PVNV(0x9c50a60) at 0x9c70f68 REFCNT = 1 FLAGS = (IOK,NOK,pIOK,pNOK) IV = 2 NV = 2 PV = 0 lanx@nc10-ubuntu:~$ perl -MDevel::Peek -e'$|=1;$e=3;$x=log(5**$e)/log( +5); Dump $x; print ("\n", ($x==$e) ? "" : "not " ,"equal\n\n"); Dump + $x;' SV = NV(0x8fde840) at 0x8fc8f68 REFCNT = 1 FLAGS = (NOK,pNOK) NV = 3 not equal SV = PVNV(0x8fa8a60) at 0x8fc8f68 REFCNT = 1 FLAGS = (NOK,pIOK,pNOK) IV = 3 NV = 3 PV = 0

        UPDATE: improved code

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1010275]
Approved by toolic
Front-paged by LanX
[Tux]: I have no idea! Read this article
[choroba]: yes, if the formula contains just +, -, *, /, and digits, calculate it, otherwise fail, or something like that.
[choroba]: or detection of malicious strings like | cmd or what was the security issue about.
[choroba]: re slow PM, yesterday half of my clicks in RATS ended in request timeout.
[Tux]: 1nickt - yes, it works oké
[Tux]: choroba as many formula's have references to other cells, that would only be possible on constants. CSV_XS has no knowledge of the contents of the rest of the document
[Tux]: But it could be an option for Spreadsheet::Read (but I am not tempted to do that. patches welcome?)
[choroba]: makes sense
[1nickt]: Tux Wow, interesting! He seems to say that there is no real protection in Excel other than common sense. Nice story about the Dutch police using the exploit to bring down criminal networks on the Dark Web!

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2017-10-18 10:58 GMT
Find Nodes?
    Voting Booth?
    My fridge is mostly full of:

    Results (244 votes). Check out past polls.