1

我对使用 MPI 例程相对较新,我很困惑为什么在下面的代码中我会根据我使用的节点数得到不同的结果。

编码:

import numpy as np
from mpi4py import MPI

def MPI_sum(comm,x):
    xsum = np.sum(x)
    vals = comm.gather(xsum,root=0)

    if rank == 0:
        s = np.sum(vals)

    s = comm.bcast(s,root=0)

    return s

comm = MPI.COMM_WORLD
size = comm.Get_size()

datalen = 80000/size
x = np.zeros(datalen) + 1. + 1e-5

xsum = MPI_sum(comm,x)
if rank == 0:
    print xsum - np.floor(xsum)

我用 1 个节点和 2 个节点运行此代码。我从 1 个节点得到的答案是:0.800000153016 我从 2 个节点得到的答案是:0.800000035219

是什么导致了这种差异?

(作为补充说明,我确实尝试将 MPI_sum 中的所有 x 数组数据传递给 root=0,然后在 root=0 上求和,这给了我正确的答案;无论节点数量如何,输出都相同。但是传递所有一个节点的数据对于我将在其中实现的代码是不实用的。)

感谢您的任何帮助!

4

1 回答 1

3

观察到的效果是由浮点运算的非关联性引起的,并不特定于 MPI 应用程序,尽管后者由于问题域的划分而往往更频繁地暴露它。观察以下内容以了解会发生什么:

>>> import numpy as np
>>> datalen = 80000
>>> x = np.zeros(datalen) + 1. + 1e-5
>>> xsum = np.sum(x)
>>> xsum - np.floor(xsum)
0.80000015301629901
>>> xsum = np.sum(x[:datalen/2]) + np.sum(x[datalen/2:])
>>> xsum - np.floor(xsum)
0.80000003521854524

换句话说,给定一台有限精度的计算机,对整个数组求和与首先分别对数组的两半求和然后对这两个和求和是不同的,无论您是否使用 MPI(如您的代码中所示)或串行(如在我的示例中)。

原因是任何时候将两个浮点数相加都会发生最后一位舍入。随着时间的推移,人们学会了处理浮点运算的这些特性。有一些特殊的求和算法可以防止类似的影响,例如Kahan 求和算法

请注意,10 -5在任何有限精度二进制计算机上都不能精确表示,因为 log 2 (10 -5 ) = -5 x log 2 (10) 并且 10 的二进制对数是一个无理数。

于 2014-04-05T00:23:05.570 回答