添加零时奇怪的 numpy.sum 行为

2024-05-08

我了解数学上等效的算术运算如何因数值错误而导致不同的结果(例如,以不同的顺序对浮点数求和)。

然而,令我惊讶的是添加零sum可以改变结果。我认为无论如何,这始终适用于浮动:x + 0. == x.

这是一个例子。我预计所有的线都恰好为零。有人可以解释为什么会发生这种情况吗?

M = 4  # number of random values
Z = 4  # number of additional zeros
for i in range(20):
    a = np.random.rand(M)
    b = np.zeros(M+Z)
    b[:M] = a
    print a.sum() - b.sum()

-4.4408920985e-16
0.0
0.0
0.0
4.4408920985e-16
0.0
-4.4408920985e-16
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
2.22044604925e-16
0.0
4.4408920985e-16
4.4408920985e-16
0.0

对于较小的值似乎不会发生M and Z.

我也确定了a.dtype==b.dtype.

这里还有一个例子,它也演示了 python 的内置功能sum行为符合预期:

a = np.array([0.1,      1.0/3,      1.0/7,      1.0/13, 1.0/23])
b = np.array([0.1, 0.0, 1.0/3, 0.0, 1.0/7, 0.0, 1.0/13, 1.0/23])
print a.sum() - b.sum()
=> -1.11022302463e-16
print sum(a) - sum(b)
=> 0.0

我正在使用 numpy V1.9.2。


简短回答:您正在看到之间的区别

a + b + c + d

and

(a + b) + (c + d)

由于浮点不准确,这并不相同。

长答案:Numpy 实现成对求和作为速度(它允许更容易矢量化)和舍入误差的优化。

可以找到numpy sum-implementationhere https://github.com/numpy/numpy/blob/master/numpy/core/src/umath/loops.c.src(功能pairwise_sum_@TYPE@)。它主要执行以下操作:

  1. 如果数组长度小于8,则进行常规for循环求和。这就是为什么在以下情况下不会观察到奇怪的结果:W < 4在您的情况下 - 在这两种情况下都将使用相同的 for 循环求和。
  2. 如果长度在 8 到 128 之间,则将总和累加到 8 个 bin 中r[0]-r[7]然后将它们相加((r[0] + r[1]) + (r[2] + r[3])) + ((r[4] + r[5]) + (r[6] + r[7])).
  3. 否则,它递归地对数组的两半求和。

因此,在第一种情况下你会得到a.sum() = a[0] + a[1] + a[2] + a[3]在第二种情况下b.sum() = (a[0] + a[1]) + (a[2] + a[3])这导致a.sum() - b.sum() != 0.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

添加零时奇怪的 numpy.sum 行为 的相关文章