使用numpy.sin时的精度问题

o2g1uqev  于 2023-06-23  发布在  其他
关注(0)|答案(2)|浏览(172)

我尝试用numpy从正弦波开始生成方波。
我遇到了一个问题:

  • 使用numpy.pi常量会产生不准确的结果
  • 使用3.14常量可以得到正确的结果

为了创建方波,取正弦波的符号,然后使用最大值函数将-1转换为0。

N = 15
x = np.arange(1, N)
s = np.maximum(np.sign(np.sin(3.14 * (x - 1))), np.zeros_like(x))
print(s)

>> [0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1.]

当在numpy中使用pi的常量时,可以得到:

N = 15
x = np.arange(1, N)
s = np.maximum(np.sign(np.sin(np.pi * (x - 1))), np.zeros_like(x))
print(s)

>> [0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 0.]

其中序列不是交替的1和0。元素越多,您可以观察到相邻的两个0以上的面片。

[0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 0. 0. 1. 0. 0. 0.]

我主要是想了解使用更精确的值如何导致不精确的结果。

rm5edbpk

rm5edbpk1#

你的计算数值不稳定。使用更高的精度不会解决问题,而只是将其隐藏得更深一点。主要问题是sin(PI * x)理论上应该总是0,但是没有 * 浮点 * 函数是完美的,所以会有错误(通常是1 ULP)。此错误会更改结果的符号。这就是你所观察到的。这个问题与精度无关。下面是你计算的几何图:

如果你只是想要交替的0-1值,你可以添加一个移位到sin函数(例如:np.maximum(np.sign(np.sin(np.pi * (x - 1) + np.pi/2)), np.zeros_like(x)))。如果移位为pi/2,则可以使用cos函数。

dnph8jn4

dnph8jn42#

一般来说,如果你想找到为什么这样的东西不工作,然后检查中间结果,原因可能会变得明显。

>>> np.sin(np.pi * (np.arange(5)))
array([ 0.0000000e+00,  1.2246468e-16, -2.4492936e-16,  3.6739404e-16, -4.8985872e-16])

因此,整数乘以pi的sin为零,上图显示了浮点数精度极限时的抖动。它可以是随机的正或负。

相关问题