IEEE 754: sqrtf() with fesetround(): different results between compilers: 0x42440a72 vs. 0x42440a73
Asked Answered
D

1

7
#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;
}

Host: Win10 x64.

Results:

Case 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 version 8.0.1 (tags/RELEASE_801/final)

Case 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 --version
gcc (GCC) 10.2.0

Case 3.

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

Case 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."

Case 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

Case 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

Questions:

  1. Why there are different results (0x42440a72 vs. 0x42440a73) between compilers?
  2. How to get the same results between compilers?
Dilatometer answered 13/9, 2020 at 12:41 Comment(4)
You can - and must post those - just don't put everything as a code block. Format the headings of the separate runs as normal text!Jocasta
@AnttiHaapala, thanks for the hint (using <pre>code</pre> pattern)!Dilatometer
Changing floating-point rounding modes is not well supported by some compilers and libraries, but one problem in your source code is that the C standard does not define the behavior if you change rounding modes with FENV_ACCESS off (C 2018 7.6.1 2). You can turn it on with #pragma STDC FENV_ACCESS ON in compilers that support it.Ringhals
Do I understand correctly that in case of FENV_ACCESS off we cannot rely on fesetround() return value because of UB? In the example above fesetround() does [falsely] return 0 (i.e. rounding direction was successfully set), but from the results we see that rounding direction was not set.Dilatometer
U
1

Why there are different results (0x42440a72 vs. 0x42440a73) between compilers?

At least with older gcc, <fenv.h> support not required.

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

When I compile with "GNU C11 (GCC) version 9.3.0 (x86_64-pc-cygwin)", the below

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

I receive the below:

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

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

How to get the same results between compilers?

Not that helpful, but do not use optional features of fenv.h or avoid select compilers.

There may exist a gcc compile time flag to help, but I am not aware of one.

Also use #pragma STDC FENV_ACCESS ON @Eric Postpischil. This may not solve this issue, but prevent related ones.

Undersheriff answered 13/9, 2020 at 15:10 Comment(1)
Both gcc and clang do not support #pragma STDC FENV_ACCESS ON. gcc: warning: ignoring '#pragma STDC FENV_ACCESS', clang: warning: pragma STDC FENV_ACCESS ON is not supported. For clang it seems that there is a patch: reviews.llvm.org/D69272. For cl: need to use #pragma fenv_access (on).Dilatometer

© 2022 - 2024 — McMap. All rights reserved.