是否有更多类似 C++ 的方法来控制超精度的处理?
C99 标准定义FLT_EVAL_METHOD
了一个编译器集宏,它定义了如何在 C 程序中发生超额精度(许多 C 编译器的行为方式仍然不完全符合对FP_EVAL_METHOD
它们定义的值的最合理解释:旧 GCC生成 387 代码的版本,生成 387 代码时的 Clang,...)。FLT_EVAL_METHOD
C11 标准中阐明了与影响有关的细微之处。
自 2011 年标准以来,C++遵循C99来定义FLT_EVAL_METHOD
(header cfloat)。
所以 GCC 应该简单地允许-fexcess-precision=standard
C++,并希望它最终会。与 C 相同的语义已经在 C++ 标准中,它们只需要在 C++ 编译器中实现。
我想对于我当前的用例,我可能会在任何情况下使用 -mfpmath=sse,据我所知,这不会导致任何过度的精度。
这是通常的解决方案。
请注意,C99 还在FP_CONTRACT
math.h 中定义了您可能想要查看的内容:它涉及以更高的精度计算某些表达式的相同问题,从完全不同的方面(现代的融合乘加指令代替)旧的 387 指令集)。这是一个编译指示,用于决定是否允许编译器用 FMA 指令替换源代码级加法和乘法(这具有以无限精度虚拟计算乘法的效果,因为这是该指令的工作方式,而不是四舍五入到类型的精度,就像使用单独的乘法和加法指令一样)。这个编译指示显然没有被纳入 C++ 标准(据我所知)。
此选项的默认值是实现定义的,有些人认为默认值是允许生成 FMA 指令(对于否则定义FLT_EVAL_METHOD
为 0 的 C 编译器)。在 C 语言中,您应该通过以下方式确保您的代码不会过时:
#include <math.h>
#pragma STDC FP_CONTRACT off
如果您的编译器记录了一个,那么 C++ 中的等效咒语。
在没有任何开关的情况下,g++ 默认行为是什么?
恐怕这个问题的答案是 GCC 的行为,比如在生成 387 代码时,是无意义的。请参阅促使 Joseph Myers 为 C 修复这种情况的情况描述。如果 g++ 没有实现-fexcess-precision=standard
,这可能意味着当编译器碰巧不得不溢出一些浮点数时,80 位计算被随机四舍五入到类型的精度- 将寄存器指向内存,导致下面的程序在程序员无法控制的某些情况下打印“foo”:
if (x == 0.0) return;
... // code that does not modify x
if (x == 0.0) printf("foo\n");
...因为省略号中的代码导致x
保存在 80 位浮点寄存器中的代码溢出到堆栈上的 64 位插槽。