代码之家  ›  专栏  ›  技术社区  ›  Kevin Spaghetti

使用numpy.sin时出现精度问题

  •  0
  • Kevin Spaghetti  · 技术社区  · 2 年前

    我正在尝试使用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.]
    

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

    2 回复  |  直到 2 年前
        1
  •  1
  •   Jérôme Richard    2 年前

    您的计算是 数值不稳定 。使用更高的精度并不能解决问题,只会稍微隐藏一点。主要问题是 sin(PI * x) 理论上应该始终为0,但不是 浮点 函数是完美的,因此存在错误(通常为1 ULP )。此错误会更改结果的符号。这就是你观察到的。这个问题与精度无关。以下是您计算内容的几何图示:

    enter image description here

    如果您只想要交替的0-1值,可以在 sin 功能(例如。 np.maximum(np.sign(np.sin(np.pi * (x - 1) + np.pi/2)), np.zeros_like(x)) )。如果换档 pi/2 ,则可以使用 cos 作用

        2
  •  1
  •   Dave Rove    2 年前

    一般来说,如果你想找到这样的东西不起作用的原因,那么检查中间结果,原因可能会变得显而易见。

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

    因此,π的整数倍的sin为零,上面显示了浮点精度极限下的抖动。它可以是积极的或消极的随机。