develooper Front page | perl.perl5.porters | Postings from February 2003

Re: [perl #20827] Unexpected scientific notation.

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
February 11, 2003 14:33
Subject:
Re: [perl #20827] Unexpected scientific notation.
Message ID:
20030211222745.GD280@Bagpuss.unfortu.net
On Mon, Feb 10, 2003 at 11:32:21PM -0000, abigail@abigail.nl (via RT) wrote:

Given that it's 5.8.0 with 64 bit IVs

>     $ perl -wle 'print 1597009560 * 1597009560'
>     2550439534731393600

multiplication will be done as IVs as it doesn't overflow
(constant folding irrelevant here)

>     $ perl -wle '$x = 1597009560; print $x * $x'
>     2550439534731393600

multiplication will be done as IVs as it doesn't overflow

>     $ perl -wle 'print 1597009560 ** 2'
>     2550439534731393600

exponentiation will be done as NVs
It will be constant folded in the peephole optimiser in op.c:

#ifdef PERL_PRESERVE_IVUV
            /* Only bother to attempt to fold to IV if
               most operators will benefit  */
            SvIV_please(sv);
#endif

IIRC this isn't quite the same constant folding as 5.6.x did.

>     $ perl -wle '$x = 1597009560; print $x ** 2'
>     2.5504395347313936e+18
> 
> I would have expected all outputs to be the same.

So would I, but stopping to think, I know what the implementation is up to.

> The fact that 2550439534731393600 is numerically the same as
> 2.5504395347313936e+18 doesn't do me any good, as it's the
> stringifaction that gives the unexpected results:
> 
>      $ perl -wle '$x = 1597009560; print "$x ** 2 = @{[$x ** 2]}"'
>      1597009560 ** 2 = 2.5504395347313936e+18
> 
> This is probably caused by the fact that $x ** 2 becomes an NV,
> but neither 1597009560 ** 2 nor $x * $x do:

If anything, the peephole optimiser should be changed, and the constant
1597009560 ** 2 left as an NV. This would make the first two the same, and
the second two both scientific notation.

> It seems like in one case (at compile time?), Perl seems to be smart enough
> to realize that 1597009560 ** 2 can be represented as an integer, while
> in another case, it doesn't figure it out.

Correctly deduced, assuming my explanation is correct.

Not switching printf to integer format was needed to preserve sanity for
values > 2**53 with 64 bit NVs and 64 bit IVs.

Your configuration has long double NVs, so I'm not sure if it would be possible
to change things whilst maintaining numeric sanity.

Sanity here being that exp (37) / 2 should not be an integer.
Actually, currently we have insanity:

$ perl5.8.0-64 -le 'print exp (37)/2'
5859571186401306
$ perl5.8.0-64 -le 'print exp (shift) /2' 37
5.85957118640131e+15

I would consider only the latter answer sane.

Nicholas Clark

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About