http://qs1969.pair.com?node_id=1229754


in reply to Re^3: Variables are automatically rounded off in perl
in thread Variables are automatically rounded off in perl

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