Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re: Variables are automatically rounded off in perl

by bart (Canon)
on Jul 24, 2016 at 10:48 UTC ( #1168424=note: print w/replies, xml ) Need Help??


in reply to Variables are automatically rounded off in perl

Somebody had to mention it. 0.30000000000000004.com

TLDR: It's not just perl. It's (virtually) every computer language out there.

(Well, Perl 6 might be just a little bit better than the others, in this regard.)

  • Comment on Re: Variables are automatically rounded off in perl

Replies are listed 'Best First'.
Re^2: Variables are automatically rounded off in perl
by syphilis (Bishop) on Jul 24, 2016 at 15:12 UTC
    Somebody had to mention it. 0.30000000000000004.com

    But that's a different issue. That one's about getting a result of 0.30000000000000004 when a result of 0.3 is "expected".

    In the OP's case, a result of 3336 was obtained though the expected (and correct) result is 3335.9999999999995.

    Cheers,
    Rob
Re^2: Variables are automatically rounded off in perl
by harangzsolt33 (Friar) on Jul 26, 2016 at 04:41 UTC

    TLDR: It's not just perl. It's (virtually) every computer language out there."

    Exactly. JavaScript works the same way. I usually avoid working with floats whenever possible. If I have to get a precise result, then I multiply my number by 1000 to push the decimal point to the right. Whatever comes after the decimal point gets rounded, and it's usually garbage.

      I've done some testing with large numbers and floats in Perl and JavaScript. Here are the results:

      use strict; use warnings; my $NUM_A = 3335.999999999995; my $NUM_B = 3335.99999999995; # Normally, a 64-bit float can have 15 significant digits, # which is the mantissa of a number. If you try to write # 16 significant digits, you will lose precision!! And # that's what happens with $NUM_A. It has 16 significant # digit, and that's too long! # In JavaScript, you can store 3335.9999999999995 which # has 17 significant digits, but the numbers turns into 3336 # once you squeeze in another '9' in that list! # # In JavaScript, the largest mantissa you can have is: # 9007199254740992. If you try to add 1 to this number, # then the addition won't register, because it gets rounded # back to the original number. lol # # In JavaScript, if you try to add # 3335.9999999999995 + 0.0000000000001, it is equal to: # 3335.9999999999995 # So the addition won't even register, because it considers # that addition insignificantly small. The result won't change. # # In perl, it turns into 3336. lol # print " ADDITION: ", 3335.9999999999995 + 0.0000000000001, "\n"; print " SUBTRACT: ", 3335.9999999999995 - 0.0000000000001, "\n"; # Let's see what perl will do with this large number: print " BIGGEST JAVASCRIPT NUMBER: ", 9007199254740992, "\n"; print " BIGGEST JAVASCRIPT NUMBER: ", 900719925474099, "\n"; print " BIGGEST JAVASCRIPT NUMBER: ", 90071992547409, "\n"; print " BIGGEST JAVASCRIPT NUMBER: ", 9007199254740, "\n"; print " BIGGEST JAVASCRIPT NUMBER: ", 900719925474, "\n"; # "print" won't display the last significan digit. # so let's try this instead: if (9007199254740988 > 9007199254740987) { print "1 BIGGER OK.\n" } # + prints fine if (9007199254740989 > 9007199254740988) { print "2 BIGGER OK.\n" } # + prints fine if (9007199254740990 > 9007199254740989) { print "3 BIGGER OK.\n" } # + prints fine if (9007199254740991 > 9007199254740990) { print "4 BIGGER OK.\n" } # + prints fine if (9007199254740992 > 9007199254740991) { print "5 BIGGER OK.\n" } # + prints fine if (9007199254740993 > 9007199254740992) { print "6 BIGGER OK.\n" } # + <<this won't print! if (9007199254740994 > 9007199254740993) { print "7 BIGGER OK.\n" } # + prints fine if (9007199254740995 > 9007199254740994) { print "8 BIGGER OK.\n" } # + prints fine if (9007199254740996 > 9007199254740995) { print "9 BIGGER OK.\n" } # + <<this won't print! # See, as we start heading above that number, # we have problems in perl as well. # You can't tell whether a number is bigger or smaller, # because the last digit get rounded when it is stored in memory. # Okay, let's talk about divisions and remainders for a sec... print " NUM_A = $NUM_A \n NUM_B = $NUM_B\n"; my $R = $NUM_B % 3330; print " NUM_B % 3330 = $R (This should be 5.99999999995, but due to t +he strange way 64-bit floats are stored, it gets \"corrupted.\" So, n +ormally you'd get 5.9999999999499778. But in perl you don't even get +that result. You just get 5.)\n\n"; # So, in order to get the same result you would get # in JavaScript, you would call FMOD() function (see below) # instead of using the % (mod) operator: print " FMOD(NUM_B, 3330) = ", FMOD($NUM_B, 3330), "\n\n"; # # This function produces the same result as the % operator # in JavaScript: C = A % B; # # Usage: C = FMOD(A, B) # sub FMOD { my ($A, $B) = @_; return $A - int($A / $B) * $B; }
        Hi,

        # In JavaScript, you can store 3335.9999999999995 which has 17 significant digits

        Perl will actually store that number correctly, as this indicates:
        C:\>perl -le "print 'ok' if 3335.9999999999995 > 3335.999999999999;" ok
        The problem is that when perl prints these numbers out it first rounds them to 15 digits - hence perl prints out the same figure for each of the 2 values featured in the above one-liner, even though perl knows that the 2 values are different:
        C:\>perl -le "print 3335.9999999999995; print 3335.999999999999;" 3336 3336
        # In JavaScript, if you try to add 3335.9999999999995 + 0.0000000000001, it is equal to 3335.9999999999995

        Same goes for perl:
        C:>perl -le "print 'ok' if 3335.9999999999995 + 0.0000000000001 == 333 +5.9999999999995;" ok
        Again, the problem is perl's commitment to outputting an approximation:
        C:\>perl -le "print 3335.9999999999995;" 3336
        # "print" won't display the last significant digit

        Yes - annoying, isn't it. Simplest way to see what a floating point value actually is, is to either:
        printf "%a", $float; or printf "%.16e", $float;
        If you want to go to the trouble of installing Math::MPFR (which requires gmp and mpfr C libraries), I've just added an nvtoa() function which will return a string representation of an NV using as few digits as are necessary. (The nvtoa function requires mpfr-4.0.0 or later.)
        For example:
        C:\>perl -MMath::MPFR=":mpfr" -le "print nvtoa(2 ** -1074);" 5e-324 C:\>perl -MMath::MPFR=":mpfr" -le "print nvtoa(sqrt 2.0);" 1.4142135623730951
        Works with __float128 and long double builds, too - though Math-MPFR-4.09 (latest CPAN release) is somewhat slower than it ought to be for these nvtypes when abs(exponent) > about 500.
        (This has been addressed in the current github version.)

        If you're using perl-5.28.x or earlier, then you also need to be aware that perl often assigns slightly incorrect values. (This is fixed in perl-5.29.4 and later, so long as $Config{d_strtod} is defined.)
        If you want to be assured that a value is assigned correctly on perl-5.28 and earlier, simplest way might be (untested) to assign that value as a string provided to POSIX::strtod.
        That is do:
        use POSIX qw(strtod); $x = strtod('1234e-5');
        instead of :
        $x = 1234e-5;
        Or, you can also use Math::MPFR:
        use Math::MPFR qw(:mpfr); $x = atonv('1234e-5');
        # So, in order to get the same result you would get in JavaScript, you would call FMOD() function (see below) instead of using the % (mod) operator

        I think this could be just 2 different languages making different choices regarding behaviour of the modulus operator when applied to fractional values.
        Someone else might be able to provide more definitive advice about that.

        Cheers
        Rob

      No, it doesn't. JavaScript does not truncate digits. Try it:

      javascript:alert(3335.9999999999995)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1168424]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (4)
As of 2020-06-05 19:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you really want to know if there is extraterrestrial life?



    Results (40 votes). Check out past polls.

    Notices?