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

Hello folks,

surprisingly to me the following string comparison of two numbers in different format (scientific, decimal) works as if not the operator "eq" but "==" would have been used for the comparsion, i.e., the variables $a and $b are compared numerically.

I would have expected that the numbers would have been converted to strings (due to the eq-operator) and that the result would be "Numbers are not equal!".

So, why does "eq" work like this and can I rely on this in general, i.e., would two numbers always numerically oompared by "eq" (e.g., it works for the two numbers 1000000 and 1_000_000 in the same manner).

perl -e '$a = 1e-3; $b = 0.001; if ( $a eq $b ) { print "Numbers are e +qual!\n" } else { print "Numbers are not equal!\n" }' Numbers are equal!

THX for any epiphany by You monks!

  • Comment on Why does this string comparison compares "numerically" and can I rely on this in general?
  • Download Code

Replies are listed 'Best First'.
Re: Why does this string comparison compares "numerically" and can I rely on this in general?
by hippo (Archbishop) on Apr 30, 2018 at 08:57 UTC
    So, why does "eq" work like this

    Because the internal representation of the two numbers is the same. Just because your code uses different formats to specify them does not affect how they are stored internally. Try this version of your code to see the values:

    perl -we '$a = 1e-3; $b = 0.001; if ( $a eq $b ) { print "$a and $b ar +e equal.\n" }'

    BTW, try to avoid $a and $b for arbitrary variables in real code because they have special meanings for sorting.

      The stringified form also depends if the values began as strings or numbers.

      $x = '1e-3'; $y = 0.001; if ( $x eq $y ) { print "$x and $y are equal.\n" } else { print "$x and $y are not equal" } print "\n"; $x = $x + 0; if ( $x eq $y ) { print "$x and $y are equal.\n" } else { print "$x and $y are not equal" }
      Result is:
      1e-3 and 0.001 are not equal 0.001 and 0.001 are equal.

      In the first comparison, $x is a string. In the second comparison, $x is numeric before it is stringified for comparison.

      The Scalar::Util documentation is useful here. https://perldoc.perl.org/Scalar/Util.html#isdual

Re: Why does this string comparison compares "numerically" and can I rely on this in general?
by haukex (Archbishop) on Apr 30, 2018 at 11:51 UTC
    $a = 1e-3; $b = 0.001; if ( $a eq $b ) { ...

    Note that this doesn't really have anything to do with eq or ==, but with how Perl handles numeric literals in its source code - they are converted to Perl's internal representation first.

    # force numbers to strings before printing: $ perl -wMstrict -le 'print "".1e-3; print "".0.001; print "".0.0_0_1; print "".0x1.0624dd2f1a9fcp-10' 0.001 0.001 0.001 0.001 # edited for brevity: $ perl -wMstrict -MDevel::Peek -le 'Dump( 1e-3 )' NV = 0.001 $ perl -wMstrict -MDevel::Peek -le 'Dump( 0.001 )' NV = 0.001 $ perl -wMstrict -MDevel::Peek -le 'Dump( 0.0_0_1 )' NV = 0.001 $ perl -wMstrict -MDevel::Peek -le 'Dump( 0x1.0624dd2f1a9fcp-10 )' NV = 0.001
    would two numbers always numerically oompared by "eq"

    If I take the question to mean "does eq do numeric comparisons automatically when presented with numbers", the answer is no, it always converts its operands to strings first (I'm ignoring overloading here).

    can I rely on this in general

    But my question would be: Why would you want to rely on this? If you want to do a numeric comparison, you should use the numeric == (always keeping in mind the limitations of floating-point numbers!*), and if you want to know if two values converted to strings are equal, use eq - and looking at the above, eq's behavior makes sense here.

    At the moment, I can't think of a case where one would want to do such an "automatic numeric comparison". Could this be an XY problem - are you perhaps trying to do something with user input? (Update: If you want a number to retain its formatting, you need to store it as a string instead of a number.)

    * Update: And if you want to know whether two numbers are approximately equal:

    $ perl -wMstrict -le ' if ( sprintf("%.3f",0.001) eq sprintf("%.3f",0.001001) ) { print "yes" } else { print "no" }' yes
Re: Why does this string comparison compares "numerically" and can I rely on this in general?
by syphilis (Archbishop) on Apr 30, 2018 at 11:30 UTC
    ... and can I rely on this in general

    If the left hand side and the right hand side stringify to the same string, then you can rely on the "eq" condition being true.
    And if the left hand side and the right hand side stringify to different strings, then you can rely on the "eq" condition being false.

    The danger lies in what you might deduce from the result of such comparisons:
    $ perl -le 'print "ok" if 1.4142135623731 eq 1.4142135623730951;' ok $ perl -le 'print "ok" if 1.4142135623731 != 1.4142135623730951;' ok
    Cheers,
    Rob