【问题标题】:IEEE 754: sqrtf() with fesetround(): different results between compilers: 0x42440a72 vs. 0x42440a73IEEE 754:带有 fesetround() 的 sqrtf():编译器之间的不同结果:0x42440a72 与 0x42440a73
【发布时间】:2020-12-31 09:13:18
【问题描述】:
#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。

结果:

案例 1。

$ 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 版本 8.0.1 (tags/RELEASE_801/final)

案例 2。

$ 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 --版本 海合会 (GCC) 10.2.0

案例 3。

cl t2.c && t2 Microsoft (R) C/C++ 优化编译器版本 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++ 优化编译器版本 19.25.28611 for x86 ... 系统无法执行指定的程序。 出现弹出窗口:“病毒和线程保护:Windows Defender Antivirus 发现威胁。获取详细信息。”

案例 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: 铿锵头 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

问题:

  1. 为什么编译器之间的结果不同(0x42440a720x42440a73)?
  2. 如何在编译器之间获得相同的结果?

【问题讨论】:

  • 您可以 - 并且必须发布这些 - 只是不要将 所有内容都作为代码块。将单独运行的标题格式化为普通文本!
  • @AnttiHaapala,感谢您的提示(使用&lt;pre&gt;code&lt;/pre&gt; 模式)!
  • 某些编译器和库不太支持更改浮点舍入模式,但源代码中的一个问题是,如果您使用 FENV_ACCESS 更改舍入模式,C 标准没有定义行为关闭(C 2018 7.6.1 2)。您可以在支持它的编译器中使用#pragma STDC FENV_ACCESS ON 将其打开。
  • 我是否理解正确,在FENV_ACCESS 关闭的情况下,由于UB,我们不能依赖fesetround() 返回值?在上面的示例中,fesetround() 确实 [错误地] 返回了 0(即成功设置了舍入方向),但从结果中我们看到未设置舍入方向。

标签: c floating-point rounding ieee-754 cl


【解决方案1】:

为什么编译器之间的结果不同(0x42440a72 与 0x42440a73)?

至少对于较旧的 gcc,不需要&lt;fenv.h&gt; 支持。

floating-point environment access in <fenv.h>, Library feature, no compiler support required.

当我使用“GNU C11 (GCC) version 9.3.0 (x86_64-pc-cygwin)”编译时,以下

#include <fenv.h>
#pragma STDC FENV_ACCESS ON

我收到以下信息:

warning: ignoring #pragma STDC FENV_ACCESS [-Wunknown-pragmas]

另见If pragma STDC FENV_ACCESS is absent, does it mean default rounding mode?pragma STDC FENV_ACCESS ON is not supported

如何在编译器之间得到相同的结果?

没那么有用,但不要使用fenv.h 的可选功能或避免选择编译器。

可能存在一个 gcc 编译时间标志来提供帮助,但我不知道。

也可以使用#pragma STDC FENV_ACCESS ON@Eric Postpischil。这可能无法解决这个问题,但会阻止相关问题。

【讨论】:

  • gcc 和 clang 都不支持#pragma STDC FENV_ACCESS ON。 gcc:warning: ignoring '#pragma STDC FENV_ACCESS',clang:warning: pragma STDC FENV_ACCESS ON is not supported。对于 clang,似乎有一个补丁:reviews.llvm.org/D69272。对于cl:需要使用#pragma fenv_access (on)
猜你喜欢
  • 2022-10-16
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-28
  • 2020-11-19
相关资源
最近更新 更多