哪种GCC优化可能会根据是否打印而改变双倍?

时间:2018-06-11 11:16:43

标签: c++ gcc floating-point compiler-optimization

我正在调试实现一种算法的代码,该算法的主循环在_ s >= u || s <= l语句为真时终止,其中sul为{{1在主循环中更新的s。在此示例中,所有三个变量始终位于double0.5之间。我不在这里包含代码,因为它不是由我编写的,并且提取MWE很难。我对这些代码在不同体系结构上表现不同感到困惑,我希望下面的线索可以帮助我缩小算法中的错误。

某些浮点舍入似乎是该bug的根本原因。以下是我到目前为止所确定的内容:

  • 该算法在x86-64上的所有优化级别上正确终止。
  • 算法在arm64,mips64和ppc64上使用-O3(未尝试其他选项级别)正确终止。
  • 算法在i686上使用-O0正确终止。
  • 算法在i686上使用-O1,-O2和-O3无限循环
  • 问题的主要观点:在算法无限循环的情况下,如果在比较1.5之前打印s,则可以使其正确终止到std::cout << s << std::endll

这里可以使用哪种编译器优化?

上述所有行为均在GNU / Linux系统上观察,并使用GCC 6.4,7.3和8.1进行复制。

1 个答案:

答案 0 :(得分:3)

由于您说您的代码在x86-64和其他指令集上按预期工作,但在i686上中断,但只有一些优化级别,可能的罪魁祸首是x86 extended precision

在x86上,浮点指令将结果存储在寄存器中,其精度高于随后将这些值存储在存储器中的精度。因此,当编译器可以重新使用已经加载到寄存器中的相同值时,与必须保存和重新加载值时相比,结果可能不同。打印值可能需要保存并重新加载。

这是well-known non-bug in GCC

GCC提供-ffloat-store命令行选项,可能会有所帮助:

  

-ffloat-store

     

不要将浮点变量存储在寄存器中,并禁止其他可能会改变浮点值是否从寄存器或内存中获取的选项。

     

这个选项可以防止诸如68000之类的机器上出现不希望的过度精度,其中浮动寄存器(68881)的精度比double应该具有的更高。同样适用于x86架构。对于大多数程序来说,多余的精度只会很好,但有些程序依赖于IEEE浮点的精确定义。在修改这些程序以将所有相关的中间计算存储到变量中之后,对这些程序使用-ffloat-store

如上所述,它不会自动让您的代码与其他指令集上的代码相同。您可能需要修改代码以将结果显式存储在变量中。