我想计算两个IEEE 754二进制64号的总和,四舍五入.为此我在下面写了C99程序:
#include <stdio.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(int c, char *v[]){
fesetround(FE_UPWARD);
printf("%a\n", 0x1.0p0 + 0x1.0p-80);
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我使用各种编译器编译并运行我的程序:
$ gcc -v
…
gcc version 4.2.1 (Apple Inc. build 5664)
$ gcc -Wall -std=c99 add.c && ./a.out
add.c:3: warning: ignoring #pragma STDC FENV_ACCESS
0x1p+0
$ clang -v
Apple clang version 1.5 (tags/Apple/clang-60)
Target: x86_64-apple-darwin10
Thread model: posix
$ clang -Wall -std=c99 add.c && ./a.out
add.c:3:14: warning: pragma STDC FENV_ACCESS ON is not supported, ignoring
pragma [-Wunknown-pragmas]
#pragma … 所有文档(在标准中)都fenv.h相当混乱,但我对feholdexcept浮点异常的"不停模式"的概念特别困惑.据我所知,在任何IEEE浮点实现中,默认情况下异常都是非信令/"不停止",并且fenv.h接口似乎无法启用信令模式,除非它是默认模式.feholdexcept除非在非IEEE系统或具有非标准扩展的系统上设置信令异常掩码,否则整个概念是无用的?
我正在编写依赖于 C(特别是 c11)四舍五入到偶数的中间关系的代码。当使用带有舍入模式的 rint 作为 FE_TONEAREST 时,我没有在 C 标准中找到说明如何使用 FE_NEAREST 处理关系的保证。ISO C 标准第 509 页指出
<fenv.h> 中的 fegetround 和 fesetround 函数提供了在 <fenv.h> 中的舍入方向宏(FE_TONEAREST、FE_UPWARD、FE_DOWNWARD、FE_TOWARDZERO)和值 0、1 表示的 IEC 60559 定向舍入模式之间进行选择的工具FLT_ROUNDS 的 、 、 2 和 3 是 IEC 60559 定向舍入模式。
但是,我在 IEC 60559 标准中找不到有关舍入模式的任何文档。在我的测试机器上,行为是在 FE_TONEAREST 中,关系四舍五入为偶数,我想确保这是由 c11 标准强制执行的,而不是实现定义的。
请考虑以下代码:
#include <fenv.h>
#include <stdio.h>
int main()
{
#pragma STDC FENV_ACCESS ON
1.0/0.0;
printf("%x\n", fetestexcept(FE_ALL_EXCEPT));
}
Run Code Online (Sandbox Code Playgroud)
我希望它打印一个非零值对应FE_DIVBYZERO,但它打印0.更改第二行main以double x = 1.0/0.0;给出预期的行为.这是允许的,还是一个bug?
编辑:对于它的价值,起初似乎在大多数现实世界的代码中,可能导致引发fenv异常的操作无法优化,因此可以安全地执行大型计算并在最后检查是否存在溢出,div-by-zero等发生了.但是,当您考虑内联和优化时,事情会变得混乱,并且会出现真正的问题.如果这样的函数在由于常量参数而总是最终除以零的情况下被内联,则gcc可能变得非常聪明并且基本上优化整个内联函数而return INFINITY;不会引发任何异常.