From: Piotr Fusik Date: Fri, 24 Jun 2005 12:47:40 +0000 (+0200) Subject: Re: [PATCH] Faster ** X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=900658e3894003c933933cc814fc7c95f6f6a2dd;p=p5sagit%2Fp5-mst-13.2.git Re: [PATCH] Faster ** From: "Piotr Fusik" Message-Id: <00b201c578af$7ad02b40$17d24dd5@piec> p4raw-id: //depot/perl@25177 --- diff --git a/pp.c b/pp.c index cb48bb8..be055a0 100644 --- a/pp.c +++ b/pp.c @@ -900,36 +900,37 @@ PP(pp_pow) we're sure it is safe; otherwise we call pow() and try to convert to integer afterwards. */ { - SvIV_please(TOPm1s); - if (SvIOK(TOPm1s)) { - bool baseuok = SvUOK(TOPm1s); - UV baseuv; + SvIV_please(TOPs); + if (SvIOK(TOPs)) { + SvIV_please(TOPm1s); + if (SvIOK(TOPm1s)) { + UV power; + bool baseuok; + UV baseuv; - if (baseuok) { - baseuv = SvUVX(TOPm1s); - } else { - const IV iv = SvIVX(TOPm1s); - if (iv >= 0) { - baseuv = iv; - baseuok = TRUE; /* effectively it's a UV now */ - } else { - baseuv = -iv; /* abs, baseuok == false records sign */ - } - } - SvIV_please(TOPs); - if (SvIOK(TOPs)) { - UV power; + if (SvUOK(TOPs)) { + power = SvUVX(TOPs); + } else { + const IV iv = SvIVX(TOPs); + if (iv >= 0) { + power = iv; + } else { + goto float_it; /* Can't do negative powers this way. */ + } + } - if (SvUOK(TOPs)) { - power = SvUVX(TOPs); - } else { - IV iv = SvIVX(TOPs); - if (iv >= 0) { - power = iv; - } else { - goto float_it; /* Can't do negative powers this way. */ - } - } + baseuok = SvUOK(TOPm1s); + if (baseuok) { + baseuv = SvUVX(TOPm1s); + } else { + const IV iv = SvIVX(TOPm1s); + if (iv >= 0) { + baseuv = iv; + baseuok = TRUE; /* effectively it's a UV now */ + } else { + baseuv = -iv; /* abs, baseuok == false records sign */ + } + } /* now we have integer ** positive integer. */ is_int = 1; @@ -945,34 +946,28 @@ PP(pp_pow) programmers to notice ** not doing what they mean. */ NV result = 1.0; NV base = baseuok ? baseuv : -(NV)baseuv; - int n = 0; - - for (; power; base *= base, n++) { - /* Do I look like I trust gcc with long longs here? - Do I hell. */ - const 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; - } - } + + if (power & 1) { + result *= base; + } + while (power >>= 1) { + base *= base; + if (power & 1) { + result *= base; + } + } SP--; SETn( result ); SvIV_please(TOPs); RETURN; } else { register unsigned int highbit = 8 * sizeof(UV); - register unsigned int lowbit = 0; - register unsigned int diff; - bool odd_power = (bool)(power & 1); - while ((diff = (highbit - lowbit) >> 1)) { - if (baseuv & ~((1 << (lowbit + diff)) - 1)) - lowbit += diff; - else - highbit -= diff; + register unsigned int diff = 8 * sizeof(UV); + while (diff >>= 1) { + highbit -= diff; + if (baseuv >> highbit) { + highbit += diff; + } } /* we now have baseuv < 2 ** highbit */ if (power * highbit <= 8 * sizeof(UV)) { @@ -980,13 +975,14 @@ PP(pp_pow) on same algorithm as above */ register UV result = 1; register UV base = baseuv; - register int n = 0; - for (; power; base *= base, n++) { - register const UV bit = (UV)1 << (UV)n; - if (power & bit) { + const bool odd_power = (bool)(power & 1); + if (odd_power) { + result *= base; + } + while (power >>= 1) { + base *= base; + if (power & 1) { result *= base; - power -= bit; - if (power == 0) break; } } SP--;