浮点计算如何确定?

浮点计算既不是关联的,也不是处理器上的分配。 所以,

(a + b) + c不等于a + (b + c)

并且a * (b + c)不等于a * b + a * c

有没有办法执行不会给出不同结果的确定性浮点计算。 它对于单处理器来说是确定性的,但是如果线程增加一个总和,它在multithreading程序中就不是确定性的,因为线程可能有不同的交错。

所以我的问题是,如何在multithreading程序中实现浮点计算的确定性结果?

浮点确定性的。 在相同硬件上运行的相同浮点运算始终产生相同的结果。 没有黑魔法,噪音,随机性,模糊测试或人们通常归因于浮点的任何其他事物。 牙仙不出现,取你的结果的低位,并在枕头下留下四分之一。

现在,也就是说,通常用于大规模并行计算的某些阻塞算法在执行浮点计算的顺序方面是不确定的,这可能导致跨运行的非位精确结果。

你能为这个做什么?

首先,确保你实际上不能忍受这种情况。 您可能尝试在并行计算中强制执行排序的许多事情都会损害性能。 就是这样。

我还要注意,尽管被阻塞的算法可能会引入一定数量的非确定性,但它们通常会提供比天真未阻塞的串行算法更小的舍入误差的结果(令人惊讶但却是真实的!)。 如果你能忍受一个天真的串行算法产生的错误,你可能会遇到并行阻塞算法的错误。

现在,如果你真的,真的,需要跨运行的完全重现性,这里有一些建议,往往不会对性能产生太大的负面影响:

  1. 不要使用可以重新排序浮点计算的multithreading算法。 问题解决了。 这并不意味着您根本不能使用multithreading算法,只需要确保每个单独的结果仅由同步点之间的单个线程触及。 请注意,如果正确完成,通过减少核心之间的D $争用,这实际上可以提高某些体系结构的性能。

  2. 在还原操作中,您可以让每个线程将其结果存储到数组中的索引位置,等待所有线程完成,按顺序累积数组的元素。 这会增加少量的内存开销,但通常可以容忍,特别是当线程数“很小”时。

  3. 找到提升并行性的方法。 而不是计算24个矩阵乘法,每个矩阵乘法使用并行算法,并行计算24个矩阵乘积,每个矩阵乘积使用串行算法。 这也有利于性能(有时非常有用)。

还有很多其他方法可以解决这个问题。 他们都需要思考和关心。 并行编程通常会。

即使使用高精度定点数据类型也不能解决使所述方程的结果具有确定性的问题(在某些情况下除外)。 正如Keith Tomposon在评论中所指出的,1/3是一个无关紧要的例子,它无法在标准的base-10或base-2浮点表示中正确存储(无论使用的精度或内存如何)。

根据特定需要,可以解决此问题(它仍然有限制)的一种解决方案是使用有理数数据类型(存储分子和分母的类型)。 基思建议GMP作为一个这样的库:

GMP是一个免费的库,用于任意精度算术,对有符号整数, 有理数和浮点数进行操作。 精度没有实际限制……

这个任务是否合适(或足够)是另一个故事……

快乐的编码。

编辑:我已经删除了我的旧答案,因为我似乎误解了OP的问题。 如果您想看到它,您可以阅读编辑历史记录。

我认为理想的解决方案是切换到每个线程都有一个单独的累加器。 这避免了所有锁定,这应该对性能产生巨大影响。 您可以在整个操作结束时简单地对累加器求和。

或者,如果您坚持使用单个累加器,一种解决方案是使用“定点”而不是浮点。 这可以通过在累加器中包含一个巨大的“偏置”项来将浮点类型锁定,以将指数锁定在固定值。 例如,如果您知道累加器永远不会超过2 ^ 32,则可以在0x1p32处启动累加器。 这将锁定小数点左边的32位精度和20位小数精度(假设为double )。 如果这不够精确,你可以给我们一个较小的偏差(假设累加器不会变得太大)或切换到long double 。 如果long double是80位扩展格式,则2 ^ 32的偏差将给出31位的小数精度。

然后,只要您想实际“使用”累加器的值,只需减去偏差项。

使用支持此类型的十进制类型或库。

尝试将每个中间结果存储在易失性对象中:

 volatile double a_plus_b = a + b; volatile double a_plus_b_plus_c = a_plus_b + c; 

这可能会对性能产生负面影响。 我建议测量两个版本。

编辑volatile的目的是禁止可能影响结果的优化,即使在单线程环境中也是如此,例如更改操作顺序或将中间结果存储在更宽的寄存器中。 它没有解决multithreading问题。

EDIT2 :还有其他需要考虑的因素

可以缩小浮动表达式,即,将其评估为primefaces操作,从而省略源代码和表达式评估方法所暗示的舍入误差。

这可以通过使用来抑制

 #include  ... #pragma STDC FP_CONTRACT off 

参考: C99标准 (大型PDF),第7.12.2和6.5节第8段。这是C99特定的; 一些编译器可能不支持它。

使用压缩十进制 。

Interesting Posts