Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Converting -4.84800000E+001 to -48.48 doesn't work... but 48.49 does

by notameadow (Initiate)
on Jan 05, 2017 at 20:30 UTC ( [id://1179036]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I have just spent better part of the day trying to work this out. It looks like a bug, but that would be quite interesting in itself. Try this:
perl -e '$a = "-4.84900000E+001"; $a += 0; $b = -48.49; print "EQ\n" i +f ($a == $b); print "$a\n$b\n";'
it gives:
EQ -48.49 -48.49
All good. Now, try this:
perl -e '$a = "-4.84800000E+001"; $a += 0; $b = -48.48; print "EQ\n" i +f ($a == $b); print "$a\n$b\n";'
gives:
-48.48 -48.48
? In my main code I am getting scientific notation values as strings, I add 0 and compare them as numbers. It all works, but not for -4.84800000E+001 (and 4.84800000E+001 too). Why? I tried some combinations like 37.37 and so on.
perl -v This is perl 5, version 22, subversion 2 (v5.22.2) built for x86_64-li +nux-thread-multi (with 33 registered patches, see perl -V for more detail)
I really do hope this is something silly on my part.

Replies are listed 'Best First'.
Re: Converting -4.84800000E+001 to -48.48 doesn't work... but 48.49 does
by choroba (Cardinal) on Jan 05, 2017 at 20:44 UTC
    As usually, the inner representation of the numbers is different:
    my $x = "-4.84800000E+001"; $x += 0; my $y = -48.48; print "EQ\n" if $x == $y; printf "%.16f\n%.16f\n", $x, $y; __END__ -48.4800000000000040 -48.4799999999999969

    See also What Every Programmer Should Know About Floating-Point Arithmetic.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Converting -4.84800000E+001 to -48.48 doesn't work... but 48.49 does
by AnomalousMonk (Archbishop) on Jan 05, 2017 at 21:11 UTC

    The problem also seems related to Perl version, but I can't say why. Trying the following code under various Perl versions I have access to ATM:

    c:\@Work\Perl\monks>perl -wMstrict -le "print 'perl version: ', $]; ;; $a = '-4.84800000E+001'; $a += 0; $b = -48.48; print 'EQ' if $a == $b; printf qq{%0.20f ?==? %0.20f \n}, $a, $b; " perl version: 5.008009 -48.48000000000000400000 ?==? -48.47999999999999700000 perl version: 5.010001 EQ -48.47999999999999700000 ?==? -48.47999999999999700000 perl version: 5.014004 EQ -48.47999999999999700000 ?==? -48.47999999999999700000

    Update: choroba has /msgd to ask if the differences in my results are due to 32- versus 64-bit build differences. As far as I can see from  perl -V (and to the best of my recollection), all the Perls I have here are 32-bit. However, the 5.8.9 I'm using is ActiveState, while the others are all Strawberries.

    Update: davido /msgd to suggest different C compilers/libraries have different internal implementations for FP handling; perhaps AS Perl was compiled with Visual Studio and Strawberry with GNU/C.


    Give a man a fish:  <%-{-{-{-<

      The problem also seems related to Perl version, but I can't say why

      It's a known bug.
      For your particular example (on Win32, perl-5.22.0):
      C:>perl -le "print scalar reverse unpack 'h*', pack 'd<', -48.48;" c0483d70a3d70a3d C:>perl -le "print scalar reverse unpack 'h*', pack 'd<', -4.848e1;" c0483d70a3d70a3e
      -48.48 is being assigned correctly, but -4.848e1 is off by one ulp.

      These errors are not uncommon and can change between perl versions.

      Cheers,
      Rob
        These errors are not uncommon and can change between perl versions.
        And C libraries and compilers and even seemingly-unrelated compiler settings.
Re: Converting -4.84800000E+001 to -48.48 doesn't work... but 48.49 does
by LanX (Saint) on Jan 05, 2017 at 23:37 UTC
    Computers can't be accurate with all fractions because Humans have too many fingers .

    update

    Now unfortunately the calculation path to the inner representation of 48.48 and 4.848e1 seem to produce different results.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      Computers can't be accurate with all fractions

      But this is no excuse for -4.848e1 and -48.48 being treated as different values.

      Cheers,
      Rob
        Yes, sure, this is not satisfactory, but the bottom line, in C, in Perl and in most other programming languages, is that you should not compare floats for equality (unless you really know very well what you're doing). To check is two such numbers shall be deemed equal, one should check that the absolute value of their difference is smaller than a certain very small value.

        Perl 6 has a rational type, in which numbers are stored internally as a numerator and a denominator, allowing for accurate comparison of decimal numbers.

        Yeah just updated it before I saw your reply.

        I think the way -48.48 is transformed into a float follows a different calculation path which rounds the last bit into another direction.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

Re: Converting -4.84800000E+001 to -48.48 doesn't work... but 48.49 does
by notameadow (Initiate) on Jan 06, 2017 at 09:03 UTC
    Thanks for all your help. I was only vaguely aware of how tricky comparing floats that looked quite round can be. Unfortunately one side of comparison is supplied by humans and the other is coming back from a device and I have no influence on neither, so will have to rely on rounding the machine side to 2f. Thanks again.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (6)
As of 2024-03-28 07:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found