python/numpy中的浮点数学不能跨机器重现

Urs*_*Urs 10 python floating-point numpy blas

比较几台不同机器上的浮点计算结果,它们始终产生不同的结果.这是一个重现行为的简化示例:

import numpy as np
from numpy.random import randn as rand

M = 1024
N = 2048
np.random.seed(0)

a = rand(M,N).astype(dtype=np.float32)
w = rand(N,M).astype(dtype=np.float32)

b = np.dot(a, w)
for i in range(10):
    b = b + np.dot(b, a)[:, :1024]
    np.divide(b, 100., out=b)

print b[0,:3]
Run Code Online (Sandbox Code Playgroud)

不同的机器会产生不同的结果

  • [-2.85753540e-05 -5.94204867e-05 -2.62337649e-04]
  • [-2.85751412e-05 -5.94208468e-05 -2.62336689e-04]
  • [-2.85754559e-05 -5.94202756e-05 -2.62337562e-04]

但我也可以得到相同的结果,例如在同一年份的两台MacBook上运行.这种情况发生在具有相同版本的Python和numpy的机器上,但不一定与相同的BLAS库链接(例如,加速Mac上的框架,Ubuntu上的OpenBLAS).但是,不同的数值库是否应该符合相同的IEEE浮点标准并给出完全相同的结果?

Ali*_*lik 5

浮点计算并不总是可重现的。

如果您使用相同的可执行映像、输入、使用相同编译器构建的库和相同的编译器设置(开关),您可能会在不同机器上的浮动计算中获得可重现的结果。

但是,如果您使用动态链接库,您可能会得到不同的结果,原因有很多。首先,正如 Veedrac在评论中指出的那样,它可能会在不同架构上为其例程使用不同的算法。其次,编译器可能会根据开关(各种优化、控制设置)生成不同的代码。甚至a+b+c会在机器和编译器之间产生不确定的结果,因为我们无法确定中间计算的评估顺序和精度。

在这里阅读为什么不能保证在不同的IEEE 754-1985实现上获得相同的结果。新标准 ( IEEE 754-2008) 试图走得更远,但它仍然不能保证不同实现之间的结果相同,因为例如它允许实现者选择何时检测到微小(下溢异常)

可以在本文中找到有关浮点确定性的更多信息。

  • 至少在 Python 级别,我们*可以*确定诸如“a + b + c”之类的评估顺序和中间精度:评估顺序是确定性的,并且中间结果被强制存储(因此不确定性由于不可预测的寄存器溢出不是问题)。*在*单*算术运算中*仍然*有可能进行双舍入,尽管这个问题正在慢慢变得越来越少...... (2认同)