什么样的 GCC 优化可能会根据是否打印来更改双精度?

What kind of GCC optimizations may change a double based on whether it is printed or not?

本文关键字:打印 是否 双精度 GCC 优化 什么样      更新时间:2023-10-16

>我正在调试实现算法的代码,该算法的主循环在语句为真时终止 à las >= u || s <= l,其中suldouble在主循环中更新。在此示例中,所有三个变量始终介于0.51.5之间。我在这里不包括代码,因为它不是我写的,提取 MWE 很难。我对代码在不同架构上的行为不同感到困惑,我希望下面的线索可以帮助我缩小算法中的错误范围。

一些浮点舍入似乎是该错误的根本原因。以下是我到目前为止所确定的:

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

什么样的编译器优化可能与这里相关?

上述所有行为都是在GNU/Linux系统上观察到的,并在GCC 6.4、7.3和8.1中重现。

由于您说您的代码在 x86-64 和其他指令集上按预期工作,但在 i686 上中断,但仅在一些优化级别下中断,因此可能的罪魁祸首是 x86 扩展精度。

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

这是GCC中一个众所周知的非错误。

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

-ffloat-store

不要在寄存器中存储浮点变量,并禁止其他选项,这些选项可能会更改浮点值是从寄存器还是存储器中获取的。

此选项可防止在诸如 68000 之类的机器上出现不希望的过分精度,其中浮动寄存器(68881 的(保持比双精度更高的精度。x86 体系结构也是如此。对于大多数程序来说,过多的精度只会有好处,但少数程序依赖于IEEE浮点的精确定义。在修改此类程序以将所有相关的中间计算存储到变量中后,对此类程序使用-ffloat-store

正如那里提到的,它不会自动让你的代码像在其他指令集上一样工作。您可能需要修改代码以将结果显式存储在变量中。