In what cases does Python complex exponentiation throw an OverflowError?

complex-numbers, floating-point, python

Solution

A look at the source for complex exponentiation shows that Python only checks for overflow at the end of the computation. Also, there's a special case for small integer exponents that uses exponentiation by squaring, which involves complex multiplication.

r.real = a.real*b.real - a.imag*b.imag;
r.imag = a.real*b.imag + a.imag*b.real;

This is the formula for complex multiplication. Note the following:

a.real*b.real - a.imag*b.imag

When `a` and `b` are very large, this becomes floating-point infinity minus floating-point infinity, which is `nan`. The `nan` results propagate, and after a few operations, the result is `(nan+nanj)`. `Py_ADJUST_ERANGE2` only sets `errno` if it sees an infinity, so it misses the overflow and goes on its way.

In summary, Python only checks the end result for overflow, not intermediate values, and this causes it to miss the overflow in the middle because it's all `nan`s by the end. The expressions that do raise `OverflowError` do so because they never try to subtract infinities, so the error is spotted by the end. It doesn't look like a deliberate design decision; you could fix it by changing the way the overflow check works.

Problem

I’m trying to figure out the pattern here: ``` >>> 1e300 ** 2 OverflowError: (34, 'Result too large') >>> 1e300j ** 2 OverflowError: complex exponentiation >>> (1e300 + 1j) ** 2 OverflowError: complex exponentiation >>> (1e300 + 1e300j) ** 2 (nan+nanj) ``` The behavior seems to be not only unspecified in theory, but also weird in practice! What explains this?

Original source