Numpy - -1的平方根留下一个小的实部
这可能是个算法的问题,但下面这段代码
numpy.power((-1+0j),0.5)
输出的结果是
(6.1230317691118863e-17+1j)
类似的表达式,比如 numpy.power(complex(-1),.5)
也得到了同样的结果,不过 numpy.sqrt(complex(-1))
却得到了我们预期的结果 1j
。很明显,结果应该没有实数部分,所以我可能漏掉了什么重要的东西,或者我需要把这个问题反馈给numpy的开发者。
如果有人问,我不能把实数部分舍去(我需要这个计算的全部精度),而且我确实需要使用这个幂函数。
3 个回答
试试 numpy.real_if_close() 这个函数。
详细信息可以查看这里: Real if close
事情是这样的,-1的平方根可以用一个公式来计算,公式是exp(i phase/2),其中phase(相位)大约是π。实际上,
>>> 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(模) + i 相位)。而cmath.sqrt(-1)
直接给出1j
,因为它使用了不同的方法,没有受到(-1+0j)**0.5
的浮点数近似问题的影响(正如TonyK所提到的)。
这是因为 numpy.power()
在处理复杂数字时的实现方式导致的一个副作用。标准库也有同样的问题。
>>> numpy.power(-1+0j, 0.5)
(6.123233995736766e-17+1j)
>>> cmath.exp(cmath.log(-1)/2)
(6.123233995736766e-17+1j)