【问题标题】:Does GCC's ffast-math have consistency guarantees across platforms or compiler versions?GCC 的 ffast-math 是否具有跨平台或编译器版本的一致性保证?
【发布时间】:2019-09-01 23:54:29
【问题描述】:

我想编写跨平台的 C/C++,它在不同的环境中具有可重现的行为。

我了解 gcc 的 ffast-math 支持各种浮点近似。这很好,但我需要两个单独编译的二进制文件才能产生相同的结果。

假设我总是使用 gcc,但对于 Windows、Linux 或其他任何东西,以及不同的编译器版本都是不同的。

是否可以保证这些编译将为相同的源代码产生相同的浮点近似值?

【问题讨论】:

    标签: gcc ieee-754 fast-math


    【解决方案1】:

    ,并不是它们允许特定的近似值,而是-ffast-math 允许编译器假设 FP 数学不是关联的。即在转换代码以允许更高效的 asm 时忽略舍入错误。

    操作顺序选择上的任何细微差异都会通过引入不同的舍入来影响结果。

    较旧的编译器版本可能会选择将 sqrt(x) 实现为 x * approx_rsqrt(x),并对 -ffast-math 进行 Newton-Raphson 迭代,因为较旧的 CPU 具有较慢的 sqrtps 指令,因此通常值得将其替换为reciprocal-sqrt + 3 或 4 的近似乘法和加法指令。这在最近 CPU 的大多数代码中通常不是这种情况,因此 即使您使用相同的调整 选项(尤其是默认的 -mtune=generic 而不是 -mtune=haswell),选择该选项可以在 GCC 版本之间更改。


    如果没有 -ffast-math,要获得确定性 FP 已经够难的了;不同操作系统上的不同库具有不同的函数实现,如sinlog(与基本操作不同,+ - * / sqrt 不需要返回“正确舍入”结果,即最大误差 0.5ulp)。

    如果您使用 x87 FP 数学为 32 位 x86 编译,临时变量 (FLT_EVAL_METHOD) 的额外精度可能会改变结果。 (-mfpmath=387-m32 的默认值)。如果你想在这里有任何希望,你会想要避免使用 32 位 x86。或者,如果您坚持使用它,也许您可​​以使用-msse2 -mfpmath=sse...

    您提到了 Windows,所以我假设您只是在谈论 x86 GNU/Linux,即使 Linux 在 许多 其他 ISA 上运行。

    但即使在 x86 中,使用 -march=haswell 编译也可以使用 FMA 指令,并且 GCC 默认为 #pragma STDC FP_CONTRACT ON(即使跨 C 语句,超出通常的 ISO C 规则允许的范围。)所以实际上即使没有 -ffast-math , FMA 可用性可以删除 x*y + z 中临时的 x*y 的舍入。


    -ffast-math:

    当对数组求和时,一个版本的 gcc 可能决定将循环展开 2(并使用 2 个单独的累加器),而具有相同选项的旧版本 gcc 可能仍按顺序求和。

    (实际上当前的 gcc 在这方面很糟糕,当它展开(不是默认情况下)时,它通常仍然使用相同的(向量)累加器,因此它不会像 clang 那样隐藏 FP 延迟。例如 https://godbolt.org/z/X6DTxK 使用不同的寄存器用于相同的变量,但它仍然只是一个累加器,在求和循环之后没有垂直加法。但希望未来的 gcc 版本会更好。gcc 版本之间在如何对 YMM 或 XMM 寄存器进行水平求和方面的差异可能会引入自动矢量化时的差异)

    【讨论】:

      猜你喜欢
      • 2014-12-14
      • 2018-08-03
      • 2016-01-15
      • 2011-11-17
      • 2013-12-10
      • 1970-01-01
      • 2015-09-01
      • 2013-05-05
      • 2013-04-01
      相关资源
      最近更新 更多