IEEE 754:带有 fesetround() 的 sqrtf():编译器之间的不同结果:0x42440a72 与 0x42440a73
IEEE 754: sqrtf() with fesetround(): different results between compilers: 0x42440a72 vs. 0x42440a73
#include <stdio.h>
#include <stdint.h>
#include <fenv.h>
#include <math.h>
int main()
{
typedef union { uint32_t u; float f; } ufloat;
ufloat val;
float arg = 2401.999999;
int r;
r = fesetround(FE_DOWNWARD);
val.f = sqrtf(arg);
printf ("FE_DOWNWARD %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_TONEAREST);
val.f = sqrtf(arg);
printf ("FE_TONEAREST %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_TOWARDZERO);
val.f = sqrtf(arg);
printf ("FE_TOWARDZERO %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_UPWARD);
val.f = sqrtf(arg);
printf ("FE_UPWARD %22.13a [0x%x] %d\n", val.f, val.u, r);
return 0;
}
主机:Win10 x64。
结果:
案例一
$ clang t2.c -o t2.clang.exe && ./t2.clang.exe
FE_DOWNWARD 0x1.8814e60000000p+5 [0x42440a73] 0
FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0
FE_TOWARDZERO 0x1.8814e60000000p+5 [0x42440a73] 0
FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0
$ clang --version
clang version 8.0.1 (tags/RELEASE_801/final)
案例二
$ gcc t2.c -o t2.gcc.exe && ./t2.gcc.exe
FE_DOWNWARD 0x1.8814e60000000p+5 [0x42440a73] 0
FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0
FE_TOWARDZERO 0x1.8814e60000000p+5 [0x42440a73] 0
FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0
$ gcc --version
gcc (GCC) 10.2.0
案例三
cl t2.c && t2
Microsoft (R) C/C++ Optimizing Compiler Version 19.25.28611 for x64
...
FE_DOWNWARD 0x1.8814e40000000p+5 [0x42440a72] 0
FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0
FE_TOWARDZERO 0x1.8814e40000000p+5 [0x42440a72] 0
FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0
案例4.
cl t2.c && t2
Microsoft (R) C/C++ Optimizing Compiler Version 19.25.28611 for x86
...
The system cannot execute the specified program.
Pop-up window appears: "Virus & thread protection: Windows Defender Antivirus found threats. Get details."
案例5.
wandbox.org: gcc HEAD 11.0.0 20200
$ gcc prog.c -Wall -Wextra -std=c99 "-lm"
FE_DOWNWARD 0x1.8814e40000000p+5 [0x42440a72] 0
FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0
FE_TOWARDZERO 0x1.8814e40000000p+5 [0x42440a72] 0
FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0
案例 6.
wandbox.org: clang HEAD 12.0.0
$ clang prog.c -Wall -Wextra -std=gnu11 "-lm"
FE_DOWNWARD 0x1.8814e40000000p+5 [0x42440a72] 0
FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0
FE_TOWARDZERO 0x1.8814e40000000p+5 [0x42440a72] 0
FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0
问题:
- 为什么编译器之间的结果不同(
0x42440a72
与 0x42440a73
)?
- 如何在编译器之间获得相同的结果?
Why there are different results (0x42440a72 vs. 0x42440a73) between compilers?
至少对于较旧的 gcc,<fenv.h>
不需要支持。
见floating-point environment access in <fenv.h>, Library feature, no compiler support required.
当我使用“GNU C11 (GCC) 版本 9.3.0 (x86_64-pc-cygwin)”编译时,以下
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
我收到以下信息:
warning: ignoring #pragma STDC FENV_ACCESS [-Wunknown-pragmas]
另见 , pragma STDC FENV_ACCESS ON is not supported
How to get the same results between compilers?
没有太大帮助,但不要使用 fenv.h
的可选功能或避免使用 select 编译器。
可能存在 gcc 编译时标志可以提供帮助,但我不知道。
也用#pragma STDC FENV_ACCESS ON
。这可能无法解决此问题,但可以防止相关问题。
#include <stdio.h>
#include <stdint.h>
#include <fenv.h>
#include <math.h>
int main()
{
typedef union { uint32_t u; float f; } ufloat;
ufloat val;
float arg = 2401.999999;
int r;
r = fesetround(FE_DOWNWARD);
val.f = sqrtf(arg);
printf ("FE_DOWNWARD %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_TONEAREST);
val.f = sqrtf(arg);
printf ("FE_TONEAREST %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_TOWARDZERO);
val.f = sqrtf(arg);
printf ("FE_TOWARDZERO %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_UPWARD);
val.f = sqrtf(arg);
printf ("FE_UPWARD %22.13a [0x%x] %d\n", val.f, val.u, r);
return 0;
}
主机:Win10 x64。
结果:
案例一
$ clang t2.c -o t2.clang.exe && ./t2.clang.exe FE_DOWNWARD 0x1.8814e60000000p+5 [0x42440a73] 0 FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0 FE_TOWARDZERO 0x1.8814e60000000p+5 [0x42440a73] 0 FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0 $ clang --version clang version 8.0.1 (tags/RELEASE_801/final)
案例二
$ gcc t2.c -o t2.gcc.exe && ./t2.gcc.exe FE_DOWNWARD 0x1.8814e60000000p+5 [0x42440a73] 0 FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0 FE_TOWARDZERO 0x1.8814e60000000p+5 [0x42440a73] 0 FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0 $ gcc --version gcc (GCC) 10.2.0
案例三
cl t2.c && t2 Microsoft (R) C/C++ Optimizing Compiler Version 19.25.28611 for x64 ... FE_DOWNWARD 0x1.8814e40000000p+5 [0x42440a72] 0 FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0 FE_TOWARDZERO 0x1.8814e40000000p+5 [0x42440a72] 0 FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0
案例4.
cl t2.c && t2 Microsoft (R) C/C++ Optimizing Compiler Version 19.25.28611 for x86 ... The system cannot execute the specified program. Pop-up window appears: "Virus & thread protection: Windows Defender Antivirus found threats. Get details."
案例5.
wandbox.org: gcc HEAD 11.0.0 20200 $ gcc prog.c -Wall -Wextra -std=c99 "-lm" FE_DOWNWARD 0x1.8814e40000000p+5 [0x42440a72] 0 FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0 FE_TOWARDZERO 0x1.8814e40000000p+5 [0x42440a72] 0 FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0
案例 6.
wandbox.org: clang HEAD 12.0.0 $ clang prog.c -Wall -Wextra -std=gnu11 "-lm" FE_DOWNWARD 0x1.8814e40000000p+5 [0x42440a72] 0 FE_TONEAREST 0x1.8814e60000000p+5 [0x42440a73] 0 FE_TOWARDZERO 0x1.8814e40000000p+5 [0x42440a72] 0 FE_UPWARD 0x1.8814e60000000p+5 [0x42440a73] 0
问题:
- 为什么编译器之间的结果不同(
0x42440a72
与0x42440a73
)? - 如何在编译器之间获得相同的结果?
Why there are different results (0x42440a72 vs. 0x42440a73) between compilers?
至少对于较旧的 gcc,<fenv.h>
不需要支持。
见floating-point environment access in <fenv.h>, Library feature, no compiler support required.
当我使用“GNU C11 (GCC) 版本 9.3.0 (x86_64-pc-cygwin)”编译时,以下
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
我收到以下信息:
warning: ignoring #pragma STDC FENV_ACCESS [-Wunknown-pragmas]
另见
How to get the same results between compilers?
没有太大帮助,但不要使用 fenv.h
的可选功能或避免使用 select 编译器。
可能存在 gcc 编译时标志可以提供帮助,但我不知道。
也用#pragma STDC FENV_ACCESS ON