我正在调试实现一个算法的代码,其主循环在la s >= u || s <= l语句为true时终止,其中s、u和l是在主循环中更新的doubles。在本例中,所有三个变量都在0.5和1.5之间。我不包括这里的代码,因为它不是我写的,提取一个MWE是困难的。我对代码在不同体系结构上的不同行为感到困惑,我希望下面的线索能够帮助我缩小算法中的错误。
一些浮点四舍五入似乎是错误的根本原因。到目前为止,我已经确定如下:
l和u进行比较之前,如果打印s (std::cout << s << std::endl),就可以正确终止。在这里,什么样的编译器优化可能是相关的?
在GNU/Linux系统上对上述行为进行了观察,并在GCC 6.4、7.3和8.1中进行了复制。
发布于 2018-06-11 11:27:10
由于您说您的代码在x86-64和其他指令集上按预期工作,但在i686上中断,但只有在某些优化级别下,可能的罪魁祸首是x86扩展精度。
在x86上,浮点指令存储比随后将这些值存储在内存中时更精确地存储寄存器。因此,当编译器可以重用已加载在寄存器中的相同值时,结果可能与必须保存和重新加载该值时不同。打印值可能需要保存和重新加载。
这是一个GCC名著“无虫”。
GCC提供了一个-ffloat-store命令行选项,该选项可能会有所帮助:
-ffloat-store不要将浮点变量存储在寄存器中,并禁止其他可能更改浮点值是从寄存器还是从内存中提取的选项。 此选项防止在机器上出现不必要的超额精度,例如68000,其中浮动寄存器( 68881)保持比双寄存器应有的更高的精度。同样,对于x86体系结构也是如此。对于大多数程序来说,过高的精度只会带来好的效果,但也有一些程序依赖于IEEE浮点的精确定义。在修改程序以将所有相关的中间计算存储到变量之后,对此类程序使用-ffloat-store。
但是,正如前面提到的,它不会自动让代码与其他指令集的工作方式相同。您可能需要修改代码以显式地将结果存储在变量中。
https://stackoverflow.com/questions/50796496
复制相似问题