我正在调试实现一种算法的代码,该算法的主循环在_ s >= u || s <= l
语句为真时终止,其中s
,u
和l
为{{1在主循环中更新的s。在此示例中,所有三个变量始终位于double
和0.5
之间。我不在这里包含代码,因为它不是由我编写的,并且提取MWE很难。我对这些代码在不同体系结构上表现不同感到困惑,我希望下面的线索可以帮助我缩小算法中的错误。
某些浮点舍入似乎是该bug的根本原因。以下是我到目前为止所确定的内容:
1.5
之前打印s
,则可以使其正确终止到std::cout << s << std::endl
和l
。这里可以使用哪种编译器优化?
上述所有行为均在GNU / Linux系统上观察,并使用GCC 6.4,7.3和8.1进行复制。
答案 0 :(得分:3)
由于您说您的代码在x86-64和其他指令集上按预期工作,但在i686上中断,但只有一些优化级别,可能的罪魁祸首是x86 extended precision。
在x86上,浮点指令将结果存储在寄存器中,其精度高于随后将这些值存储在存储器中的精度。因此,当编译器可以重新使用已经加载到寄存器中的相同值时,与必须保存和重新加载值时相比,结果可能不同。打印值可能需要保存并重新加载。
GCC提供-ffloat-store
命令行选项,可能会有所帮助:
-ffloat-store
不要将浮点变量存储在寄存器中,并禁止其他可能会改变浮点值是否从寄存器或内存中获取的选项。
这个选项可以防止诸如68000之类的机器上出现不希望的过度精度,其中浮动寄存器(68881)的精度比double应该具有的更高。同样适用于x86架构。对于大多数程序来说,多余的精度只会很好,但有些程序依赖于IEEE浮点的精确定义。在修改这些程序以将所有相关的中间计算存储到变量中之后,对这些程序使用
-ffloat-store
。
如上所述,它不会自动让您的代码与其他指令集上的代码相同。您可能需要修改代码以将结果显式存储在变量中。