Numpy arange浮点数不一致性

3
我有一个相当简单的numpy任务:创建一个长数组,每个元素增加0.001。当然,np.arange是答案。我将自己限制在默认精度(float64)。对结果的一个简单检查是,数组的每1000个元素应具有相同的小数部分。我通过绘图进行检查(请参见附图中的蓝线),但事实并非如此。
tmin = 212990552.75436273
tmax = 213001474.74473435
tbins = np.arange(tmin, tmax, 0.001)
plt.plot(tbins[::1000] % 1)

嗯,我想...浮点数怪物又来了。我的起始值很大,但不是那么大以至于会破坏64位浮点数。根据我的直觉,我尝试以下操作,我认为应该是相同的:

nbins = tmin + np.arange(0, tmax-tmin, 0.001)
plt.plot(nbins[::1000] % 1)

看这里!就有一个差异。在数组的大约10^7个元素中,差异单调地增加到0.14。请注意,由于tmin为x.xxx36273,我希望所有数字都是x.xxx36273格式。nbins符合该要求,tbins不符合。

In [68]: tbins[-1]
Out[68]: 213001474.60374644

In [69]: nbins[-1]
Out[69]: 213001474.74436274

向那些精通 numpy 的大师们呼唤——为什么会发生这种情况?

Drift seen in the decimal part - blue line is tbins, green line is nbins

2个回答

6
您基本上是正确的;如果您关心数组元素的精确小数位,请使用第二种方法。
在您的第一个尝试中,tbins = np.arange(tmin, tmax, 0.001),您将大型和小型浮点数混合在单个计算中。给定元素的精确值被计算为先前元素和0.001的总和。这个先前的值总是比0.001大得多,因此这个求和将不会很准确(在进行浮点加法时,为获得最佳精度,两个操作数应具有相同数量级)。
在您的第二次尝试中,nbins = tmin + np.arange(0, tmax-tmin, 0.001),np.arange(0,tmax-tmin,0.001)部分的求和都非常准确,因为巨大的数字tmin被省略了,只在最后添加。每个元素的最后一个添加tmin将具有较差的准确性,这意味着最终,每个元素都经历了一次与低精度的操作。将其与第一次尝试进行比较,给定元素的值具有所有先前元素的累积误差。也就是说,数组中位于较远位置的元素越糟糕(如您的图所证实)。

2

数组的每1000个元素应该具有相同的小数部分

对于实际数字是正确的,但对于浮点值则不然。您获得的浮点值并不总是与您期望的实际数字匹配。例如,您期望tbins [1]是数字212990552.75536273,但实际上您得到的是最接近的float64值212990552.75536272

In [58]: tbins[0]
Out[58]: 212990552.75436273

In [59]: tbins[1]
Out[59]: 212990552.75536272

In [60]: tbins[0] + 0.001
Out[60]: 212990552.75536272

In [61]: 212990552.75536273
Out[61]: 212990552.75536272

没问题,我的问题有两个:1)np.arange的实现似乎会导致这种差异在连续加法中累积,2)如果我使用不同的方法创建数组,仍然使用float64,那么浮点误差要小得多(在10^-7级别而不是10^-2)。 - VBB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接