Skip to content

Commit c0eeaee

Browse files
committed
gh-156695: Improve accuracy of complex powers with small negative integer exponents
1 parent 48e9342 commit c0eeaee

1 file changed

Lines changed: 21 additions & 3 deletions

File tree

Objects/complexobject.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,11 +357,29 @@ c_powu(Py_complex x, long n)
357357
static Py_complex
358358
c_powi(Py_complex x, long n)
359359
{
360-
if (n >= 0)
360+
if (n > 0)
361361
return c_powu(x,n);
362-
else
363-
return c_powu(_Py_c_quot(c_1, x), -n);
364362

363+
Py_complex r = _Py_c_quot(c_1, c_powu(x, -n));
364+
if (errno == EDOM
365+
|| (isfinite(r.real) && isfinite(r.imag)
366+
&& (r.real != 0.0 || r.imag != 0.0)))
367+
return r;
368+
369+
/* gh-156695: x**|n| left the exponent range although the result is
370+
representable. Redo it with x scaled to exponent zero; both the
371+
scaling and its undoing are exact. */
372+
double m = fabs(x.real) > fabs(x.imag) ? fabs(x.real) : fabs(x.imag);
373+
if (m == 0.0 || !isfinite(m))
374+
return r;
375+
376+
int e;
377+
frexp(m, &e);
378+
Py_complex w = {ldexp(x.real, -e), ldexp(x.imag, -e)};
379+
r = _Py_c_quot(c_1, c_powu(w, -n));
380+
r.real = ldexp(r.real, (int)(e * n));
381+
r.imag = ldexp(r.imag, (int)(e * n));
382+
return r;
365383
}
366384

367385
double

0 commit comments

Comments
 (0)