Python Numpy总和(Numpy 1.15.4,与MKL挂钩)
我正在运行来自Anaconda的Python/Numpy(1.15.4)的最新版本,该版本与MKL链接。我使用以下ε:Python Numpy总和(Numpy 1.15.4,与MKL挂钩),python,numpy,intel-mkl,Python,Numpy,Intel Mkl,我正在运行来自Anaconda的Python/Numpy(1.15.4)的最新版本,该版本与MKL链接。我使用以下ε: epsilon = 2**(-53) 所以1.0+ε等于1.0。然后我定义了下面的numpy数组,除了前8个元素等于1之外,它用epsilon填充 import numpy as np n = 1000000 a = np.full(n, epsilon) a[0:8] = 1.0 如果你用从左到右的经典约化计算数组的和,你应该得到8.0,因为所有的ε都不会随着约化的进行而
epsilon = 2**(-53)
所以1.0+ε等于1.0。然后我定义了下面的numpy数组,除了前8个元素等于1之外,它用epsilon填充
import numpy as np
n = 1000000
a = np.full(n, epsilon)
a[0:8] = 1.0
如果你用从左到右的经典约化计算数组的和,你应该得到8.0,因为所有的ε都不会随着约化的进行而改变。但我很惊讶地看到这一点
print(np.sum(a))
给你8.00000000011008,这不是我所期望的。我试着把这些放在中间,并在数组的末尾检查总数是否没有倒退,但没有变化。你知道怎么算吗
PS:我很清楚浮点运算很棘手,而且+与浮点无关,这使得归约的结果取决于求和的顺序。但我无法找出这里使用的求和顺序。如注释中所述,
numpy
使用成对求和。因此,当调用堆栈开始解析时,在递归两两求和结束时,求和(大致)如下所示:
(1+1) + (1+1) + (1+1) + (1+1) + (epsilon + epsilon) + ... + (epsilon + epsilon)
(2+2) + (2+2) + (2*epsilon) + (2*epsilon) + ... + (2*epsilon)
(4+4) + (4*epsilon) + (4*epsilon) + ... + (4*epsilon)
8 + (8*epsilon) + (8*epsilon) + ... + (8*epsilon)
8 + (16*epsilon) + (16*epsilon) + ... + (16*epsilon)
...
8 + (999992*epsilon)
您认为1.0+epsilon
等于1.0
是正确的。人们很容易认为,x+epsilon==x
对于所有x
。当x
为“大”时,它确实有效,但当x==epsilon
时(即epsilon+epsilon!=epsilon
)它不有效。因此,epsilon+epsilon
术语将开始堆积:
In [27]: epsilon = 2**(-53)
In [28]: 1.0 + epsilon == 1.0
Out[28]: True
In [29]: 2.0 + epsilon == 2.0
Out[29]: True
In [30]: epsilon + epsilon == epsilon
Out[30]: False
In [31]: epsilon
Out[31]: 1.1102230246251565e-16
In [32]: epsilon + epsilon
Out[32]: 2.220446049250313e-16
In [33]: 123*epsilon
Out[33]: 1.3655743202889425e-14
我不能完全得到numpy的答案,但我们可以非常接近:
In [36]: 8 + (999992*epsilon)
Out[36]: 8.000000000111022
In [62]: def pairwise_sum(arr):
...: if len(arr) <= 2:
...: return sum(arr)
...: midpoint = len(arr)//2
...: first_half = arr[:midpoint]
...: second_half = arr[midpoint:]
...: return pairwise_sum(first_half) + pairwise_sum(second_half)
...:
In [63]: pairwise_sum(a)
Out[63]: 8.0000000001110205
[36]中的8+(99992*epsilon)
Out[36]:8.000000000111022
在[62]中:定义成对求和(arr):
…:如果len(arr)我知道浮点运算很复杂,但是1.0+ε应该等于1.0,8.0+ε也应该等于1,即使使用浮点算术OK,我现在看到你的点了1+epsilon==1
是True
但是设置epsilon=0
确实会退出8
,正如回答者随机评论的那样:numpy的总和并没有做简单的求和(但也没有那么昂贵)。但我现在没有联系。编辑啊,它是。@sascha:它非常接近我要找的东西。我想知道Numpy在这里做什么。上面的维基条目说这是Numpy的默认设置,并链接到。但是关于这个话题(当前的工作…)似乎有一些牵引力,所以我不会按照所有这些路径来解释当前的状态/添加答案。