Front page | perl.perl5.porters |
Postings from February 2003
Re: [perl #20827] Unexpected scientific notation.
Thread Previous
|
Thread Next
From:
hv
Date:
February 11, 2003 19:10
Subject:
Re: [perl #20827] Unexpected scientific notation.
Message ID:
200302120312.h1C3ChS02613@crypt.compulink.co.uk
Nicholas Clark <nick@unfortu.net> wrote:
:> $ 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
Hmm, should this not special case integer power of an integer, and other
calculations that we can guarantee should give an integer? And leave it
to the special-casing to handle the conversion rather than this separate
blanket check? It seems quite correct for 1.4142...(30) ** 2 to give 2.000,
and I think I'd be happy for sin(0) to return 0.000.
: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.
I agree they should be the same. I think the answer though is to move the
optimisation (hmm, correction) to where it belongs.
: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.
I'd agree.
The simplistic patch below breaks no tests here. Is this the direction
we should be going?
Since I was looking at the code anyway, it occurred that it seems a shame
not to use direct multiplication for small numbers other than pow(2^m, n).
I'd have thought that integer powers with overlarge results other than
powers of two would be quite rare, so I think this should also be a win
for any cases we can quickly enough detect would fit in a UV; the second
patch below (over the first, but independent) is an attempt at implementing
that using a simple bitsize test, which also breaks no tests here. Comments
likewise welcomed.
Do we have a macro for 'index of the highest bit set in a UV'? ISTR there
are processors with an opcode for this ...
Also, when we know C<bit> is set, wouldn't C< power -= bit > be faster
mostwheres than C< power &= ~bit >?
And fifthly, should be returning (IV)1 when power is (IV)0, regardless
of the type (assuming non-zero) of the base?
Hugo
--- pp.c.old Tue Feb 11 02:14:06 2003
+++ pp.c Wed Feb 12 03:00:32 2003
@@ -879,7 +879,11 @@
PP(pp_pow)
{
- dSP; dATARGET; tryAMAGICbin(pow,opASSIGN);
+ dSP; dATARGET;
+#ifdef PERL_PRESERVE_IVUV
+ bool is_int = 0;
+#endif
+ tryAMAGICbin(pow,opASSIGN);
#ifdef PERL_PRESERVE_IVUV
/* ** is implemented with pow. pow is floating point. Perl programmers
write 2 ** 31 and expect it to be 2147483648
@@ -920,8 +924,10 @@
goto float_it; /* Can't do negative powers this way. */
}
}
- /* now we have integer ** positive integer.
- foo & (foo - 1) is zero only for a power of 2. */
+ /* now we have integer ** positive integer. */
+ is_int = 1;
+
+ /* foo & (foo - 1) is zero only for a power of 2. */
if (!(baseuv & (baseuv - 1))) {
/* We are raising power-of-2 to postive integer.
The logic here will work for any base (even non-integer
@@ -963,6 +969,7 @@
}
SP--;
SETn( result );
+ SvIV_please(TOPs);
RETURN;
}
}
@@ -973,6 +980,10 @@
{
dPOPTOPnnrl;
SETn( Perl_pow( left, right) );
+#ifdef PERL_PRESERVE_IVUV
+ if (is_int)
+ SvIV_please(TOPs);
+#endif
RETURN;
}
}
--- pp.c Wed Feb 12 03:00:32 2003
+++ pp.c.new Wed Feb 12 02:58:23 2003
@@ -971,7 +971,49 @@
SETn( result );
SvIV_please(TOPs);
RETURN;
- }
+ } else {
+ register unsigned int highbit = 8 * sizeof(UV);
+ register unsigned int lowbit = 0;
+ register unsigned int diff;
+ while ((diff = (highbit - lowbit) >> 1)) {
+ if (baseuv & ~((1 << (lowbit + diff)) - 1))
+ lowbit += diff;
+ else
+ highbit -= diff;
+ }
+ /* we now have baseuv < 2 ** highbit */
+ if (power * highbit <= 8 * sizeof(UV)) {
+ /* result will definitely fit in UV, so use UV math
+ on same algorithm as above */
+ UV result = 1;
+ UV base = baseuv;
+ int n = 0;
+ for (; power; base *= base, n++) {
+ UV bit = (UV)1 << (UV)n;
+ if (power & bit) {
+ result *= base;
+ /* Only bother to clear the bit if it is set. */
+ power &= ~bit;
+ /* Avoid squaring base again if we're done. */
+ if (power == 0) break;
+ }
+ }
+ SP--;
+ if (baseuok || !(power & 1))
+ /* answer is positive */
+ SETu( result );
+ else if (result <= (UV)IV_MAX)
+ /* answer negative, fits in IV */
+ SETi( -(IV)result );
+ else if (result == (UV)IV_MIN)
+ /* (2's complement assumption) special case IV_MIN */
+ SETi( IV_MIN );
+ else
+ /* answer negative, doesn't fit */
+ SETn( -(NV)result );
+ RETURN;
+ }
+ }
}
}
}
Thread Previous
|
Thread Next