为什么 np.sin(np.pi)的结果不为 0?

2019-01-31 15:59:46 +08:00
 EdwardChu
import numpy as np

print(np.sin(np.pi))
print(np.sin(0.5*np.pi))

结果分别是
1.2246467991473532e-16
1.0
4706 次点击
所在节点    Python
5 条回复
nyanyh
2019-01-31 16:05:00 +08:00
LGA1150
2019-02-01 02:35:43 +08:00
因为π不能用有限空间的浮点数表示,只是一个近似值,所以你只能得到一个很接近 0 的值,而不是 0
同理 tan(π/2)
这叫 Catastrophic Cancellation
这也是比较浮点数时不能用==的原因
至于为什么第二个可以输出 1.0,是因为前面的 1.0000...占据了有效数字位(双精度可以保证 15~16 个有效数字),使误差被舍去了
LGA1150
2019-02-01 03:08:16 +08:00
#2 又查了下资料发现 Catastrophic Cancellation 好像不是这个意思。。
necomancer
2019-03-04 14:20:58 +08:00
因为 Numpy 主打数值计算,精度误差不可避免。希望 sin(pi) 是精确值可以考虑 Mathematica 或者 SymPy:

In [1]: import sympy

In [2]: sympy.pi
Out[2]: pi

In [3]: sympy.sin
Out[3]: sin

In [4]: sympy.sin(sympy.pi)
Out[4]: 0
necomancer
2019-03-04 14:35:51 +08:00
至于为什么 pi/2 更准:

In [1]: 1.0 == 1.0
Out[1]: True

In [2]: 1.0 == 1.0+1e-16
Out[2]: True

In [3]: 1.0 == 1.0+1e-15
Out[3]: False

In [4]: 1.0 == 1.0+1e-16
Out[4]: True

In [5]: 1.0 == 1.0+1.2e-16
Out[5]: False

具体代码可以去查查
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/ieee754/dbl-64/s_sin.c;hb=HEAD#l281

do_sin 函数里似乎用了麦克劳林级数。所以返回的都是近似值。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/532190

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX