Python 为什么x<;=x错误?
这个标题有点误导,因为它不完全是x和x,而是x和0.3;但是,这些值应该相同 我有:Python 为什么x<;=x错误?,python,numpy,precision,Python,Numpy,Precision,这个标题有点误导,因为它不完全是x和x,而是x和0.3;但是,这些值应该相同 我有: arr = np.arange(0, 1.1, 0.1) 我收到: arr[arr <= 0.3] > array([0., 0.1, 0.2]) arr[arr数组([0,0.1,0.2]) 正确的结果应该是: arr[arr <= 0.3] > array([0., 0.1, 0.2, 0.3]) arr[arr数组([0,0.1,0.2,0.3]) 我还没有偶然发现这个问
arr = np.arange(0, 1.1, 0.1)
我收到:
arr[arr <= 0.3]
> array([0., 0.1, 0.2])
arr[arr数组([0,0.1,0.2])
正确的结果应该是:
arr[arr <= 0.3]
> array([0., 0.1, 0.2, 0.3])
arr[arr数组([0,0.1,0.2,0.3])
我还没有偶然发现这个问题。我知道它与浮点精度有关……但我在这里能做些什么?不要依赖于比较浮点数是否相等(除非你确切知道你在处理什么浮点数)。 因为您知道用于生成数组的步长是0.1
arr = np.arange(0, 1.1, 0.1)
您可以将阈值0.3增加步长的一半,以找到一个安全介于arr
中的值之间的新阈值:
In [48]: stepsize = 0.1; arr[arr < 0.3+(stepsize/2)]
Out[48]: array([ 0. , 0.1, 0.2, 0.3])
所以数组中的第四个值略大于0.3
In [40]: arr = np.arange(0,1.1, 0.1)
In [41]: arr[3]
Out[41]: 0.30000000000000004
请注意,舍入可能不是可行的解决方案。例如, 如果
arr
具有数据类型float128
:
In [53]: arr = np.arange(0, 1.1, 0.1, dtype='float128')
In [56]: arr[arr.round(1) <= 0.3]
Out[56]: array([ 0.0, 0.1, 0.2], dtype=float128)
现在四舍五入不会产生小于0.3的数字:
In [55]: arr.round(1)[3]
Out[55]: 0.30000000000000000001
Unutbu指出了主要问题。你应该避免比较浮点数,因为它们有舍入误差 然而,这是许多人遇到的一个问题,因此有一个函数可以帮助您解决这个问题;
np.isclose
在您的情况下,这将导致:
arr[np.logical_or(arr <= 0.3, np.isclose(0.3, arr))]
>>> array([0., 0.1, 0.2, 0.3])
arr[np.logical\u或(arr>>数组([0,0.1,0.2,0.3])
在这种情况下,这可能不是最好的选择,但了解此函数可能会有所帮助
旁注:
如果没有人向您解释过,为什么会发生这种情况。基本上,计算机以二进制形式保存所有内容,但0.1是二进制形式的周期数,这意味着计算机无法保存所有数字(因为有无限多个)。十进制形式的等价物为:
1/3+1/3+1/3=0.33333+0.33333+0.33333=0.99999
哪一个不是1呢…
arr[arr.round(1)所以,在进行任何比较之前,我是否应该总是对数字进行四舍五入?浮点数之间的等价性总是一件冒险的事情。@Xiphias取决于您的用例-一种方法是将上面的值存储为0-10…并使用普通整数,因为您知道精度,而整数没有浮点数shennigans-但这可能不实用np.lin对于浮点范围,空格
通常比np.arange
好得多,特别是它可以更好地控制端点,但它不会使您避免所有舍入错误。即使您不知道步长,也可以执行类似arr的操作[arr我不知道如何量化np.arange(…)
中的值与理想的十进制值之间的距离。根据浮点数的不同,连续浮点数之间的差距会发生变化,可能会大于sys.float\u info.epsilon
。例如,x=10.3;(np.nextafter(x,np.inf)-x)>sys.float\u info.epsilon
。是的……我会帮我可怜的大脑一个忙,不要去想:)这里有一个例子,addsys.float\u info.epsilon
是不够的:x=1.83;arr=np.arange(x,x+1.1,0.1);arr[arr]
In [55]: arr.round(1)[3]
Out[55]: 0.30000000000000000001
arr[np.logical_or(arr <= 0.3, np.isclose(0.3, arr))]
>>> array([0., 0.1, 0.2, 0.3])