我了解由于数值误差(例如,以不同顺序对浮点求和),在数学上等效的算术运算如何导致不同的结果。
但是,令我惊讶的是,将零加到sum可以更改结果。我认为无论哪种情况,这对于浮动广告始终有效x + 0. == x。
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和的较小值似乎不会发生Z。
M
我也确定a.dtype==b.dtype。
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
和
(a + b) + (c + d)
由于浮点数的不准确性而不同。
长答案: Numpy实现了成对求和,以优化速度(它使矢量化更容易)和舍入误差。
numpy sum-implementation可以在这里找到(函数pairwise_sum_@TYPE@)。它基本上执行以下操作:
numpy sum-implementation
如果数组的长度小于8,则执行常规的for-loop求和。这就是为什么W < 4在您的情况下不会观察到奇怪结果的原因-两种情况下都将使用相同的for循环求和。 如果长度在8到128之间,则会将总和累加到8个bin中,r[0]-r[7]然后将它们相加((r[0] + r[1]) + (r[2] + r[3])) + ((r[4] + r[5]) + (r[6] + r[7]))。 否则,它将对数组的两部分进行递归求和。 因此,在第一种情况下,您得到,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。
for-loop
((r[0] + r[1]) + (r[2] + r[3])) + ((r[4] + r[5]) + (r[6] + r[7]))
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