python - Numpy:dot(a,b) 和 (a*b).sum() 之间的区别

标签 python numpy scipy precision floating-accuracy

对于一维 numpy 数组,这两个表达式应该产生相同的结果(理论上):

(a*b).sum()/a.sum()
dot(a, b)/a.sum()

后者使用dot() 并且速度更快。但是哪个更准确呢?为什么?

一些上下文如下。

我想使用 numpy 计算样本的加权方差。 我在 another answer 中找到了 dot() 表达式, 并附有一条评论,指出它应该更准确。但是那里没有给出任何解释。

最佳答案

Numpy dot 是调用您在编译时链接的 BLAS 库(或构建自己的库)的例程之一。这一点的重要性在于 BLAS 库可以使用乘法累加运算(通常是融合乘加)来限制计算执行的舍入次数。

采取以下措施:

>>> a=np.ones(1000,dtype=np.float128)+1E-14 
>>> (a*a).sum()  
1000.0000000000199948
>>> np.dot(a,a)
1000.0000000000199948

不准确,但足够接近。

>>> a=np.ones(1000,dtype=np.float64)+1E-14
>>> np.dot(a,a)
1000.0000000000176  #off by 2.3948e-12
>>> (a*a).sum()
1000.0000000000059  #off by 1.40948e-11

np.dot(a, a) 将是两者中更准确的一个,因为它使用的浮点舍入数大约是原始 (a*a) 的一半。 sum() 确实如此。

Nvidia 的一本书中有以下 4 位精度的示例。 rn代表四舍五入到最接近的4位:

x = 1.0008
x2 = 1.00160064                    #    true value
rn(x2 − 1) = 1.6006 × 10−4         #    fused multiply-add
rn(rn(x2) − 1) = 1.6000 × 10−4     #    multiply, then add

当然, float 不会以 10 为基数四舍五入到小数点后第 16 位,但您明白了。

np.dot(a,a) 与一些额外的伪代码放在上面的符号中:

out=0
for x in a:
    out=rn(x*x+out)   #Fused multiply add

(a*a).sum() 是:

arr=np.zeros(a.shape[0])   
for x in range(len(arr)):
    arr[x]=rn(a[x]*a[x])

out=0
for x in arr:
    out=rn(x+out)

从这里很容易看出,与 np.dot(a,a)(a*a).sum() 对数字进行四舍五入的次数是其两倍。这些微小的差异相加可以细微地改变答案。可以找到其他示例 here .

关于python - Numpy:dot(a,b) 和 (a*b).sum() 之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18092984/

相关文章:

python - 实现常微分方程组的循环

python - 正则表达式匹配多个正向先行组

python - 将有限的记录分组,其余的分组为其他

python - 为什么 Python 函数可以返回本地声明的数组而 C 不能?

Python使用列表中的项目迭代创建过滤器表达式

python - 根据行逐步对 Numpy Python 矩阵进行排序

python - 如果某一列相同,则将一行中的空值与其他行归入空值

python - 插值由其角节点已知的 3D 表面并使用颜色图对其着色

python 更改数字格式 ndarray 许多位

python - 这是 scipy.interpolate.interp1d 中的错误吗?