我有一个相当简单的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
大师 - 为什么会这样?
答案 0 :(得分:5)
你基本上是正确的;如果你关心数组元素的精确小数,请使用第二种方法。
在您第一次尝试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
。最后一个$wmi = Get-WMIObject -Class Win32_DCOMApplicationSetting -Filter "AppID='{00020906-0000-0000-C000-000000000046}'" -EnableAllPrivileges
$wmi.AuthenticationLevel = 2
$wmi.put()
添加到每个元素将具有较差的准确性,这意味着最终,每个元素将经历一个操作,准确性较差。将其与第一次尝试进行比较,其中给定元素的值具有所有先前元素的累积误差。也就是说,数组中的元素位置越远,它就越差(如图所示)。
答案 1 :(得分:2)
数组的每1000个元素应该具有相同的小数部分
对于实际数字而言,这是正确的,但对于浮点值则不然。您获得的浮点值并不总是与您期望的实际数字相匹配。例如,您希望tbins[1]
为数字212990552.75536273,但您会得到212990552.75536272
,这是最接近的float64值:
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