代码之家  ›  专栏  ›  技术社区  ›  gspr

什么样的gcc优化可以根据是否打印而改变double?[副本]

  •  0
  • gspr  · 技术社区  · 8 年前

    我正在调试实现算法的代码,该算法的主循环在语句la时终止 s >= u || s <= l 是真的,在哪里 s ,请 u 和 l 是 double 在主循环中更新的。在这个例子中,所有三个变量总是介于 0.5 和 1.5 .我不包括这里的代码,因为它不是我写的,提取一个MWE很困难。我对代码在不同的体系结构上表现的不同感到困惑,我希望下面的线索可以帮助我缩小算法中的错误。

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

    • 该算法在x86-64的所有优化级别上都正确终止。
    • 算法在arm64、mips64和ppc64上以-o3(未尝试其他opt级别)正确终止。
    • 算法在I686上以-O0正确终止。
    • 算法 无限循环 i686上有-o1、-o2和-o3。
    • 主要问题: 在算法无限循环的情况下,如果 S 已打印( std::cout << s << std::endl )在它与 我 和 u .

    什么样的编译器优化在这里是相关的?

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

    1 回复  |  直到 8 年前
        1
  •  3
  •   user743382    8 年前

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

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

    这是一个 well-known non-bug in GCC .

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

    -法洛特商店

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

    此选项可防止在诸如68000这样的机器上出现不必要的过多精度,其中浮动寄存器(68881的)比双精度寄存器要保持更高的精度。与x86体系结构类似。对于大多数程序来说,过多的精度只起到很好的作用,但有一些程序依赖于IEEE浮点的精确定义。使用 -法洛特商店 对于这些程序,在修改它们之后,将所有相关的中间计算存储到变量中。

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