【问题标题】:Why is sin(180) not zero when using python and numpy?为什么使用 python 和 numpy 时 sin(180) 不为零?
【发布时间】:2013-09-05 21:45:04
【问题描述】:

有谁知道为什么下面不等于0?

import numpy as np
np.sin(np.radians(180))

或:

np.sin(np.pi)

当我将它输入 python 时,它给了我 1.22e-16。

【问题讨论】:

  • 浮点舍入误差。
  • Pi 不能完全表示为浮点数,因此 sin(pi) 不会完全为零。
  • 有修复方法还是需要将其转换为 int?
  • 你应该用np.allclose检查值:np.allclose(np.sin(np.pi), 0)
  • @ViktorKerkez:您应该将其发布为答案。我会写一个以防您不了解它,如果您稍后再回来,请删除它。

标签: python numpy trigonometry


【解决方案1】:

数字π 不能完全表示为浮点数。所以,np.radians(180) 不给你π,它给你3.1415926535897931

sin(3.1415926535897931) 实际上类似于1.22e-16

那么,你是怎么处理的呢?

您必须计算出或至少猜测适当的绝对和/或相对误差界限,然后您写的不是x == y

abs(y - x) < abs_bounds and abs(y-x) < rel_bounds * y

(这也意味着您必须组织计算,以使相对误差相对于y 大于x。在您的情况下,因为y 是常数0,这很简单——只是向后做。)

Numpy 提供了一个函数,可以在整个数组中为您执行此操作,allclose

np.allclose(x, y, rel_bounds, abs_bounds)

(这实际上检查了abs(y - x) &lt; abs_ bounds + rel_bounds * y),但这几乎总是足够的,如果不是,您可以轻松地重新组织您的代码。)

在你的情况下:

np.allclose(0, np.sin(np.radians(180)), rel_bounds, abs_bounds)

那么,你怎么知道正确的界限是什么?没有办法在 SO 答案中教你足够的错误分析。维基百科的Propagation of uncertainty 提供了高级概述。如果你真的不知道,你可以使用默认值,1e-5 relative 和 1e-8 absolute。

【讨论】:

  • 我实际上对错误分析有很好的了解,所以这很有帮助。
  • 这个特定位置的错误几乎完全等于 np.radians(180) 中的错误。该误差可能约为 0.5 到 1.0 ULP(最后一个单位),或大约 3.14 * DBL_EPSILON,或大约 7e-16。我的误差估计是最坏情况估计,因此实际误差要小一点也就不足为奇了。请参阅这篇文章了解血腥细节(以及一些关于这个结果真的很酷的想法):randomascii.wordpress.com/2014/10/09/…
【解决方案2】:

一种解决方案是在计算 sin 和 cos 时切换到 sympy,然后使用 sp.N(...) 函数切换回 numpy:

>>> # Numpy not exactly zero
>>> import numpy as np
>>> value = np.cos(np.pi/2)
6.123233995736766e-17

# Sympy workaround
>>> import sympy as sp
>>> def scos(x): return sp.N(sp.cos(x))
>>> def ssin(x): return sp.N(sp.sin(x))

>>> value = scos(sp.pi/2)
0

只记得在使用 scos 和 ssin 函数时使用 sp.pi 而不是 sp.np。

【讨论】:

    【解决方案3】:

    遇到同样的问题,

    import numpy as np
    
    print(np.cos(math.radians(90)))
    
    >> 6.123233995736766e-17
    

    并尝试过,

    print(np.around(np.cos(math.radians(90)), decimals=5))
    
    >> 0
    

    在我的情况下工作。我设置十进制 5 不会丢失太多信息。正如您可以想到的那样,轮函数在 5 位数值后去掉。

    【讨论】:

      【解决方案4】:

      试试这个...它将任何低于给定微小值的东西归零...

      import numpy as np
      
      def zero_tiny(x, threshold):
          if (x.dtype == complex):
              x_real = x.real
              x_imag = x.imag
              if (np.abs(x_real) < threshold): x_real = 0
              if (np.abs(x_imag) < threshold): x_imag = 0 
              return x_real + 1j*x_imag
          else:
              return  x if (np.abs(x) > threshold) else 0
      
      value = np.cos(np.pi/2)
      print(value)
      value = zero_tiny(value, 10e-10)
      print(value)
      
      value = np.exp(-1j*np.pi/2)
      print(value)
      value = zero_tiny(value, 10e-10)
      print(value)
      

      【讨论】:

        【解决方案5】:

        简单。

        np.sin(np.pi).astype(int)
        np.sin(np.pi/2).astype(int)
        np.sin(3 * np.pi / 2).astype(int)
        np.sin(2 * np.pi).astype(int)
        

        返回

        0
        1
        0
        -1
        

        【讨论】:

        • 您正在强制进行类型强制,这对 OP 没有帮助。虽然这会产生sin(pi) == 0,但也会产生sin(pi/4) == 0
        猜你喜欢
        • 1970-01-01
        • 2018-10-14
        • 1970-01-01
        • 2012-03-28
        • 2017-06-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多