有谁知道为什么以下不等于0?
import numpy as np
np.sin(np.radians(180))
要么:
np.sin(np.pi)
当我进入python它给我1.22e-16。
数字π
不能完全表示为浮点数。所以,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) < 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。
一种解决方案是在计算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。
试试这个...它将任何低于给定的微小值的零点归零......
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)
问题不在于pi的舍入误差。请注意,余弦不会出现问题:
In [2]: np.sin(np.pi)
Out[2]: 1.2246467991473532e-16 != 0.
In [3]: np.cos(np.pi)
Out[3]: -1.0 == -1.
问题更加复杂。它与处理器内部pi的精度有关。这是在这里发现并解释的:https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/