python - 为什么 NumPy 在对零填充数组求和时给出不同的结果?

标签 python numpy wolfram-mathematica

我计算了一个数组和同一数组的零填充版本的总和:

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) < 8xx 中的值从左到右求和:

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/

相关文章:

Python:在编辑器中正确获取\\u00bd

python - 运行 `pip install` 的 Ubuntu 给出错误 'The following required packages can not be built: * freetype'

python - 根据特定列值绘制 pandas 数据框的多行的快速方法

python - 以 3x3D 数组为索引的 numpy 直方图

python - Numpy 中的矩阵乘法(将 2d 转换为 3d)

python - 如何在python中检查raw_input是否为整数、字符串和日期

python - 嵌套字典存储和一维 numpy 数组的矩阵乘法

wolfram-mathematica - 在mathematica中操作列表中的一个元素

wolfram-mathematica - Mathematica 中为数学书制作图形的简单编程技术/技巧?

wolfram-mathematica - 优化游戏生活