在什么情况下Python复数指数抛出一个OverflowError?

时间:2013-08-14 22:18:25

标签: python floating-point complex-numbers

我正试图弄清楚这里的模式:

>>> 1e300 ** 2
OverflowError: (34, 'Result too large')
>>> 1e300j ** 2
OverflowError: complex exponentiation
>>> (1e300 + 1j) ** 2
OverflowError: complex exponentiation
>>> (1e300 + 1e300j) ** 2
(nan+nanj)

这种行为似乎不仅在理论上没有说明,而且在实践中也很奇怪!是什么解释了这个?

3 个答案:

答案 0 :(得分:6)

查看复数取幂的source表明Python仅在计算结束时检查溢出。此外,小整数指数有一个特例,它通过平方使用取幂,这涉及复数乘法。

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

这是复数乘法的公式。请注意以下事项:

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

ab非常大时,这会变为浮点无穷大减去浮点无穷大,即nannan个结果会传播,经过几次操作后,结果为(nan+nanj)。如果Py_ADJUST_ERANGE2看到无穷大,errno只会设置nan,所以它会错过溢出并继续前进。

总之,Python只检查溢出的最终结果,而不检查中间值,这会导致它错过中间的溢出,因为它最后都是OverflowError。引发{{1}}的表达式会这样做,因为它们从不尝试减去无穷大,因此最终会发现错误。它看起来不像是一个刻意的设计决定;你可以通过改变溢出检查的工作方式来修复它。

答案 1 :(得分:2)

好的,我很确定我想出来了。

首先,我注意到一些看起来有些荒谬的事情:

>>> (1e309j)**2
(nan+nanj)
>>> (1e308j)**2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: complex exponentiation

有趣。也许这根本不与复指数有关。

>>> (1e309)**2
inf
>>> (1e308)**2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Result too large')

更有趣。让我们看看Python对1e3091e308的看法:

>>> (1e308)
1e+308
>>> (1e309)
inf

最后,

>>> (1e309)**2
inf
>>> (1e309j)**2
(nan+nanj)

>>> (float('inf') + 1j) ** 2
(nan+nanj)

>>> (1e309j)
infj
>>> (1e309j)**2
(nan+nanj)

inf的任何操纵都会给我们inf。看起来复数(a + bi)的实现不太倾向于给inf,而更多的是给(nan + nanj)。因此,通常会返回inf的内容会返回(nan + nanj)我不确定为什么会这样,也许是对Python inf和{{{ 1}}可以跳进去。

简而言之,数字最终会停止溢出,并开始返回nan。使用inf进行计算很简单,但数字附近的计算不是很好!这就是为什么inf1e309**2不起作用的原因。当与复数匹配时,这(无论出于何种原因)给出1e308 ** 2。我只是通过玩控制台才发现这一点 - 我很乐意看到更彻底的解释!

编辑:@ user2357112给出了更好的理由。计算复指数的方式可以包括(nan + nanj)的计算,其返回inf - inf。我会把它留下来显示模式,但他的答案给出了推理。


作为旁注,我发现这很有趣:

nan

答案 2 :(得分:-1)

Python整数值可以自动推广到任意精度的长度:

>>> (10**300)**2
1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

由于IEEE floating point

的限制,浮点值会溢出
>>> float(10**300)**2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Result too large')

Python复合体的组件是一个float类,受到相同的溢出:

>>> isinstance(complex(1).real,float)
True
>>> isinstance(complex(1).imag,float)
True

采用通常的最大double precision值:

>>> max_double=1.7976931348623157e+308

大多数步骤会在浮点范围范围内增加该值,并获得inf

>>> max_double*10
inf
>>> max_double*max_double
inf
>>> max_double*max_double*max_double*max_double
inf
>>> max_double++10**(308-15)
inf

如果在FP窗口之外,则mantisa和exponent不会改变:

>>> md+10**(308-17)
1.7976931348623157e+308
>>> max_double**1.0000000000000001
1.7976931348623157e+308

可以看到溢出:

>>> max_double**1.000000000000001
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Result too large')

但是作为stated in the documents,它的应用不一致:

  

由于缺乏浮点异常的标准化   在C中处理时,大多数浮点运算也不会被检查。

在这里可以看到:

>>> (1e300+1e300j)*(1e300+1e300j)
(nan+infj)
>>> (1e300+1e300j)**2
(nan+nanj)