better power implementation

This commit is contained in:
Guido van Rossum 1996-01-12 01:22:56 +00:00
parent cf3d1087d1
commit 39739ea0ed

View file

@ -316,38 +316,74 @@ float_divmod(v, w)
return mkvalue("(dd)", div, mod); return mkvalue("(dd)", div, mod);
} }
double powu(x, n)
double x;
long n;
{
double r = 1.;
double p = x;
long mask = 1;
while (mask > 0 && n >= mask) {
if (n & mask)
r *= p;
mask <<= 1;
p *= p;
}
return r;
}
double powi(x, n)
double x;
long n;
{
if (n > 10000 || n < -10000)
return pow(x, (double) n);
else if (n > 0)
return powu(x, n);
else
return 1./powu(x, -n);
}
static object * static object *
float_pow(v, w, z) float_pow(v, w, z)
floatobject *v; floatobject *v;
floatobject *w; object *w;
floatobject *z; floatobject *z;
{ {
double iv, iw, ix; double iv, iw, ix;
iv = v->ob_fval; long intw;
iw = w->ob_fval;
/* XXX Doesn't handle overflows if z!=None yet; it may never do so :( /* XXX Doesn't handle overflows if z!=None yet; it may never do so :(
* The z parameter is really only going to be useful for integers and * The z parameter is really only going to be useful for integers and
* long integers. Maybe something clever with logarithms could be done. * long integers. Maybe something clever with logarithms could be done.
* [AMK] * [AMK]
*/ */
/* Sort out special cases here instead of relying on pow() */ iv = v->ob_fval;
if (iw == 0.0) { /* x**0 is 1, even 0**0 */ iw = ((floatobject *)w)->ob_fval;
if ((object *)z!=None) { intw = (long)iw;
ix=fmod(1.0, z->ob_fval); if (iw == intw) {
if (ix!=0 && z->ob_fval<0) ix+=z->ob_fval; errno = 0;
} ix = powi(iv, intw);
else ix=1.0;
return newfloatobject(ix);
} }
if (iv == 0.0) { else {
if (iw < 0.0) { /* Sort out special cases here instead of relying on pow() */
err_setstr(ValueError, "0.0 to a negative power"); if (iw == 0.0) { /* x**0 is 1, even 0**0 */
return NULL; if ((object *)z!=None) {
ix=fmod(1.0, z->ob_fval);
if (ix!=0 && z->ob_fval<0) ix+=z->ob_fval;
}
else ix=1.0;
return newfloatobject(ix);
} }
return newfloatobject(0.0); if (iv == 0.0) {
if (iw < 0.0) {
err_setstr(ValueError, "0.0 to a negative power");
return NULL;
}
return newfloatobject(0.0);
}
errno = 0;
ix = pow(iv, iw);
} }
errno = 0;
ix = pow(iv, iw);
CHECK(ix); CHECK(ix);
if (errno != 0) { if (errno != 0) {
/* XXX could it be another type of error? */ /* XXX could it be another type of error? */