Numpy中虚幂运算的意外结果

2024-10-03 13:28:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用numpy制作FFT硬件加速器的原型。当我调试基本2x2案例时,我注意到一些奇怪的事情

根据我能找到的每个计算器,e^(-I*pi)等于-1

但是,当我有numpydonp.exp(-1j*np.pi)时,它返回(-1-1.2246467991473532e-16j)

我看不出这个数字,但它看起来不像-1,当你把-1加进去时,它看起来也不像0

我在这里使用的在线计算器是不是错了?或者我记错了数学


Tags: fftnumpy硬件nppi数字数学事情
2条回答

这是一个浮点错误- -1.2246467991473532e-16-0.00000000000000012246467991473532,对于大多数意图和目的0:

import numpy as np

number = np.exp(-1j * np.pi)
print(number) # (-1-1.2246467991473532e-16j)

number = round(number.real, 10) + round(number.imag, 10) * 1j
print(number) # (-1+0j)

虽然这是真的𝑒−𝑖𝜋=cos(−𝜋) + 𝑖 罪(−𝜋) = −1,np.exp(-1j * np.pi)传递给np.exp函数的实际上是而不是−𝑖𝜋, 这就是为什么你得不到零

相反,np.pi是对的近似值𝜋 好到大约16位,它有一个相对误差𝜋 10岁以下的儿童−16

和1.2246467991473532 × 10−16虽然很小(也许就您的目的而言,它“足够接近”零),但它远不是最小的浮点数,而最小的浮点数远低于10−300

np.exp(-1j * np.pi)的虚部中看到的不仅是np.pi的sin值的一个很好的近似值(相对误差小于10−16),但实际上大约是np.pi中的绝对误差,近似于𝜋!

你怎么知道? np.pi的实际值为3.14159265358979311599796346854418515161590576171875,您可以通过打印高达106位的数字看到这一点(超过了在不同IEEE 754二进制64浮点数之间消除歧义的需要,对于3.141592653589793来说已经足够好了,但这可以显示精确的十进制扩展):

>>> '%.106g' % (np.pi,)
'3.141592653589793115997963468544185161590576171875'
>>> '%.106g' % (np.imag(np.exp(-1j * np.pi)),)
'-1.22464679914735320717376402945839660462569212467758006379625612680683843791484832763671875e-16'

将它们排成一行,并完全精确地添加教科书:

  3.141592653589793115997963468544185161590576171875
+ 0.000000000000000122464679914735320717376402945839660462569212467758006379625612680683843791484832763671875
                                                       
  3.141592653589793238462643383279505878966979117714660462569212467758006379625612680683843791484832763671875
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我们这里有超过30个数字是正确的

为什么这样做有效? 它之所以有效是因为𝑥 近的𝜋 罪(𝑥) = (𝜋 − 𝑥) + 𝑂((𝜋 − 𝑥)³),通过泰勒展开式。 所以当我们计算sin(np.pi)=sin(𝜋 + 𝛿) 对于一些小的绝对误差𝛿, 我们得到𝜋 − (𝜋 + 𝛿) + 𝑂(𝛿³) ≈ 𝛿.


然而,请注意,正弦函数是病态的近𝜋. 如果你想知道什么是罪(𝑥) 是什么时候𝑥 近在咫尺𝜋, 但实际上你有𝑥⋅(1 + 𝛿) 对于一些小的相对误差𝛿 在输入中(可能是由于较早的舍入误差,或由于较早的系列截断,或由于测量仪器的限制,或由于任何其他类型的近似),您将返回sin(𝑥⋅(1 + 𝛿)) = 罪(𝑥)⋅(1 + 𝜀) 相对误差𝜀 在输出中,以及𝜀 可能任意大,即使𝛿 它很小

在最坏的情况下,如果你在某一点上评估罪恶𝑥 近的𝜋 比如np.pi当你想要什么的时候(𝜋), 你会得到一个无限的“相对误差”,因为没有有限的数字𝜀 以致于罪恶(𝑥) = 罪(𝜋)⋅(1 + 𝜀); 罪(𝜋) 是零和罪(𝑥) 事实并非如此

因此,您应该警惕依赖于在近似点附近计算sin的计算𝜋—不是因为浮点数,而是因为sin函数本身在那里是病态的

相反,cos在近距离内条件良好𝜋: 输入中的小错误会缩小到输出中更小的错误,这就是np.cos(np.pi)仍然返回的原因−一,

相关问题 更多 >