2009/11/3 David Lee <david....@ecmwf.int>:
> Although I've used perl for many years, I've just been surprised (in the
> unpleasant sense) by a recent event.  Given a variable, say "$int", which is
> a growing integer, I would expect "print $int" to print it as a simple
> integer; indeed it usually does so.  But when its size takes it from 15
> decimal digits to 16 decimal digits, that "print" flips the output into
> scientific notation:
>   999999999999997
>   999999999999998
>   999999999999999
>   1e+15
>   1e+15
>
> Ouch.  The surprise is especially nasty when this output data is then used
> as input data for another program that expects an integer.
>
> This is consistent across a variety of OSes (although all perl 5.8.8).
>
> I eventually managed to track down a way to achieve the desired result with
> a non-obvious "printf" format.  (I leave that, and its clear user-oriented
> explanation, as an exercise for the reader!)
>
> I'm not aware of any documentation about this surprise. Is this a program
> bug or a documentation bug?  (Or a self bug?)

I would guess that these numbers are being stored in floats, and that
these floats are 64-bit double precision, with 53 bits of mantissa.
That means that there are just under 16 decimal digits of precision in
these numbers. print and friends seem to automatically print no more
than 15 digits of precision:

H:\>perl -e "my $i = 999999999999997; print $i, ' ',$i+4,qq[\n];"
999999999999997 1e+015

The first number is 15 digits long so it is printed normally. The
second is 16 digits long, so the first 15 digits are printed in
scientific notation.

You probably want to use bignums instead. If you are dealing with
large integers, where precision down to the units place is important,
you definitely want bignums and not floats.

H:\>perl -e "use bignum; my $i = 999999999999997; print $i, ' ',$i+4,qq[\n];"
999999999999997 1000000000000001

the bignum pragma makes $i into a Math::BigInt object rather than a
floating-point value.

Your solution (a non-obvious printf format) is a bad one because while
it solves the problem of output, it doesn't solve the problem of
representation. As soon as you try to store an integer bigger than
2^53 (approximately 9e15) you will lose significance:

Here $i is a 15-digit number:
H:\>perl -e "my $i = 999999999999997; printf qq[%.16g %.16g\n],$i, $i+4;"
999999999999997 1000000000000001

So we've successfully printed 16 digits here, but when we try to go
further and make $i a 16-digit number the maths starts to fail:

H:\>perl -e "my $i = 9999999999999992; printf qq[%.16g %.16g\n],$i, $i+5;"
9999999999999992 9999999999999996

2 + 5 = 6 according to this computer, because we've gone beyond the
exactly representable range of the 64-bit floats on this machine.

In answer to your question, the behaviour of print is probably the
correct behaviour, since there's no point printing more precision than
you store. So it's a self bug.

Phil

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to