Numpy - 平方根的-1留下了一个小实部

14

也许这是一个算法问题,但以下代码片段

numpy.power((-1+0j),0.5)

会产生以下输出结果:

(6.1230317691118863e-17+1j)

类比表达式,例如 numpy.power(complex(-1),.5) 会得到相同的结果,然而 numpy.sqrt(complex(-1)) 得到了期望的结果 1j。显然结果不应该有实部,所以我是否遗漏了关键点或者需要向 numpy 开发人员报告此问题。

如果有人问,我不能四舍五入去掉实部(我需要完整精度进行计算),而且我需要使用幂函数。


4
你说的“我需要完全精度进行这个计算”是什么意思?你提供的数值比我的电脑上的机器精度还要小:np.finfo(np.complex).eps == 2.2204460492503131e-16。请问是否正确? - Katriel
@katrielalex 我的意思是,当没有实部时,就不应该有任何实部。也许精度不是正确的词,但例如,此结果稍后将被插入到复 erf 中,而后续结果对于实部的存在或不存在非常敏感(此脚本用于量子物理计算)。我知道,例如,root(2) 的精度受到比这更大的数字的限制,但在这种情况下,如果有任何意义,结果相当精确。 - crasic
1
大多数复杂浮点函数(例如在标准C库中,其中“power = cpow”在这种情况下来自)的精度通常仅以|error| / |value|指标来说明。在该指标下,上述结果是浮点数中能够达到的最好结果。如果您需要更多,则必须手动加入额外的知识。 - pv.
3个回答

15

计算平方根为-1时,实际上会计算出 exp(i phase/2),其中相位(-1的相位)大约为 π。

>>> import cmath, math
>>> z = -1+0j
>>> cmath.phase(z)
3.141592653589793
>>> math.cos(_/2)
6.123233995736766e-17

这表明-1的相位只有在1e-17左右才为π;相位除以2也仅大约为π/2,其余弦值也仅大约为0,因此你的结果(结果的实部是该余弦值)。

问题最终源于浮点数只有一个固定的、有限的数量。 π不在浮点数列表中,因此只能近似表示。π/2也无法精确表示,因此-1的平方根的实部是浮点数近似的π/2的余弦(因此余弦值与0不同)。

因此,Python对于numpy.power(complex(-1), .5)的近似值最终是由浮点数的限制所致,并且可能在许多语言中都会出现。

你观察到的与数的幂的实现通过浮点数限制相连。在你的例子中,通过计算复数的模和参数来计算平方根(基本上通过对数函数返回log(module) + i phase)。另一方面,cmath.sqrt(-1)给出了确切的1j,因为它使用了不同的方法,并且不会遭受(-1+0j)**0.5的浮点近似问题(正如TonyK所建议的那样)。


9
这是实现numpy.power()用于复数时的一个副作用。标准库也存在同样的问题。
>>> numpy.power(-1+0j, 0.5)
(6.123233995736766e-17+1j)
>>> cmath.exp(cmath.log(-1)/2)
(6.123233995736766e-17+1j)

sqrt是一个单独的函数吗?我总觉得它调用了power函数。 - crasic
14
一般而言,复杂的“power”函数需要计算实数对数和三角函数。但是“sqrt”函数只需要解几个二次方程。因此,一个好的实现会提供一个自定义的“sqrt”函数,比“power”更快且更准确。 - TonyK

5
尝试使用numpy.real_if_close()函数。详情请见:Real if close

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接