Skip to content

Commit 4b9a2dc

Browse files
authored
bpo-44698: Restore complex pow behaviour for small integral exponents (GH-27772)
1 parent c2c857b commit 4b9a2dc

File tree

3 files changed

+37
-21
lines changed

3 files changed

+37
-21
lines changed

Diff for: Lib/test/test_complex.py

+28
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,34 @@ def test_pow(self):
269269
except OverflowError:
270270
pass
271271

272+
def test_pow_with_small_integer_exponents(self):
273+
# Check that small integer exponents are handled identically
274+
# regardless of their type.
275+
values = [
276+
complex(5.0, 12.0),
277+
complex(5.0e100, 12.0e100),
278+
complex(-4.0, INF),
279+
complex(INF, 0.0),
280+
]
281+
exponents = [-19, -5, -3, -2, -1, 0, 1, 2, 3, 5, 19]
282+
for value in values:
283+
for exponent in exponents:
284+
with self.subTest(value=value, exponent=exponent):
285+
try:
286+
int_pow = value**exponent
287+
except OverflowError:
288+
int_pow = "overflow"
289+
try:
290+
float_pow = value**float(exponent)
291+
except OverflowError:
292+
float_pow = "overflow"
293+
try:
294+
complex_pow = value**complex(exponent)
295+
except OverflowError:
296+
complex_pow = "overflow"
297+
self.assertEqual(str(float_pow), str(int_pow))
298+
self.assertEqual(str(complex_pow), str(int_pow))
299+
272300
def test_boolcontext(self):
273301
for i in range(100):
274302
self.assertTrue(complex(random() + 1e-6, random() + 1e-6))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Restore behaviour of complex exponentiation with integer-valued exponent of
2+
type :class:`float` or :class:`complex`.

Diff for: Objects/complexobject.c

+7-21
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,7 @@ c_powu(Py_complex x, long n)
172172
static Py_complex
173173
c_powi(Py_complex x, long n)
174174
{
175-
Py_complex cn;
176-
177-
if (n > 100 || n < -100) {
178-
cn.real = (double) n;
179-
cn.imag = 0.;
180-
return _Py_c_pow(x,cn);
181-
}
182-
else if (n > 0)
175+
if (n > 0)
183176
return c_powu(x,n);
184177
else
185178
return _Py_c_quot(c_1, c_powu(x,-n));
@@ -523,19 +516,12 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
523516
return NULL;
524517
}
525518
errno = 0;
526-
// Check if w is an integer value that fits inside a C long, so we can
527-
// use a faster algorithm. TO_COMPLEX(w, b), above, already handled the
528-
// conversion from larger longs, as well as other types.
529-
if (PyLong_Check(w)) {
530-
int overflow = 0;
531-
long int_exponent = PyLong_AsLongAndOverflow(w, &overflow);
532-
if (int_exponent == -1 && PyErr_Occurred())
533-
return NULL;
534-
if (overflow == 0)
535-
p = c_powi(a, int_exponent);
536-
else
537-
p = _Py_c_pow(a, b);
538-
} else {
519+
// Check whether the exponent has a small integer value, and if so use
520+
// a faster and more accurate algorithm.
521+
if (b.imag == 0.0 && b.real == floor(b.real) && fabs(b.real) <= 100.0) {
522+
p = c_powi(a, (long)b.real);
523+
}
524+
else {
539525
p = _Py_c_pow(a, b);
540526
}
541527

0 commit comments

Comments
 (0)