我计算了一个数组和同一数组的零填充版本的总和:
import numpy as np
np.random.seed(3635250408)
n0, n1 = int(2**16.9), 2**17
xx = np.random.randn(n0)
yy = np.zeros(n1)
yy[:n0] = xx
sx, sy = np.sum(xx), np.sum(yy)
print(f"sx = {sx}, sy = {sy}") # -> sx = -508.33773983674155, sy = -508.3377398367416
print(f"sy - sx:", sy - sx) # -> sy - sx: -5.68434188608e-14
print("np.ptp(yy[:n0] - xx) =", np.ptp(yy[:n0] - xx)) # -> 0
为什么我没有得到相同的结果?
有趣的是,我能够在 Mathematica 中显示类似的效果。我正在使用 Python 3.6(支持 MKL 的 Anaconda 5.0)和 Numpy 1.13.3。也许,这可能是 MKL 问题?
更新:@rich-l 和 @jkim 指出舍入问题可能是原因。我不相信,因为添加零不应该改变 float (当调查该大小的数据集时出现问题 - 偏差明显更大)。
最佳答案
浮点运算是 not associative :
In [129]: ((0.1+0.2)+0.3) == (0.1+(0.2+0.3))
Out[129]: False
因此添加项目的顺序会影响结果。
numpy.sum
通常使用pairwise summation 。当数组的长度为 less than 8 时,它会恢复为朴素求和(从左到右)或when summing over a strided axis .
由于成对求和递归地将序列分为两组, 添加零填充会影响序列划分的中点,因此 更改值的添加顺序。由于浮点 算术不结合,零填充会影响结果。
例如,考虑
import numpy as np
np.random.seed(3635250408)
n0, n1 = 6, 8
xx = np.random.randn(n0)
# array([ 1.8545852 , -0.30387171, -0.57164897, -0.40679684, -0.8569989 ,
# 0.32546545])
yy = np.zeros(n1)
yy[:n0] = xx
# array([ 1.8545852 , -0.30387171, -0.57164897, -0.40679684, -0.8569989 ,
# 0.32546545, 0. , 0. ])
xx.sum()
和yy.sum()
不是相同的值:
In [138]: xx.sum()
Out[138]: 0.040734223419930771
In [139]: yy.sum()
Out[139]: 0.040734223419930826
In [148]: xx.sum() == yy.sum()
Out[148]: False
自 len(xx) < 8
, xx
中的值从左到右求和:
In [151]: xx.sum() == (((((xx[0]+xx[1])+xx[2])+xx[3])+xx[4])+xx[5])
Out[151]: True
自 len(yy) >= 8
, pairwise summation用于计算yy.sum()
:
In [147]: yy.sum() == (yy[0]+yy[1]+yy[2]+yy[3])+(yy[4]+yy[5]+yy[6]+yy[7])
Out[147]: True
相关 NumPy 开发人员讨论:
numpy.sum
不使用Kahan也不是 Shewchuk 求和(由 math.fsum
使用)。我相信这些算法会
在您提出的零填充问题下产生稳定的结果,但我还不够专业,无法肯定地说。
关于python - 为什么 NumPy 在对零填充数组求和时给出不同的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47200953/