9

I've run into an issue with floating-point comparisons. When comparing a value with NaN using the < operator, I expect the FE_INVALID flag to be set. The < operator should raise the flag according to the C11 standard (and also according to IEEE-754):

The isless macro determines whether its first argument is less than its second argument. The value of isless(x, y) is always equal to (x) < (y); however, unlike (x) < (y), isless(x, y) does not raise the "invalid" floating-point exception when x and y are unordered.

Here is an example program to reproduce my issue:

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

int main()
{
    volatile float a = 12.0f;
    volatile float b = NAN;
    volatile int   c;

    feclearexcept(FE_ALL_EXCEPT);

    c = (a < b);

    if (fetestexcept(FE_INVALID))
        printf("FE_INVALID\n");
    else
        printf("Not invalid\n");

    return 0;
}

On my machine (Linux, march=broadwell) it returns "Not invalid". I compiled it using GCC v7.2.0, using the -std=c11 option (not using it didn't change anything in the result). The emitted x86 instruction is UCOMISS which is only raising exceptions for signalling NaNs - I would expect to see COMISS as that would raise the exception on all NaN comparisons, as NaNs are unordered no matter whether they're signalling or not.

Did I make a mistake in my code or forget some compiler option to make the behavior IEEE-compliant? Could it be a bug (or performance optimization) in the compiler to ignore the need to raise an exception here?

Stefan Mach
  • 121
  • 5
  • 1
    FWIW with MSVC the output is "FE_INVALID" and `c` is 0 although I commented out the pramga because it is not recognised. – Weather Vane Feb 07 '19 at 11:30
  • 1
    Corner: Insure `feclearexcept(FE_ALL_EXCEPT);` returns zero. – chux - Reinstate Monica Feb 07 '19 at 11:41
  • 1
    Check `__STDC_IEC_559__`. "An implementation that defines _ _STDC_IEC_559_ _ shall conform to the specifications in this annex." (IEEE-compliant? ) If `__STDC_IEC_559__` is not defined, code is not specified to behave as desired. Only mistake then is an incorrect expectation. – chux - Reinstate Monica Feb 07 '19 at 11:47
  • @WeatherVane that's strange, but at least it works for you :) @chux just checked `feclearexcept`, it returns 0. Also very good point about IEEE-compliance. (Un)fortunately, `__STDC_IEC_559__` is defined, so the issue lies somewhere else.. – Stefan Mach Feb 07 '19 at 12:06

1 Answers1

3

OK so I took the plunge and got the most recent GCC version (8.2) running.

The code behaves as expected when compiled under GCC 8.2.0, so I'll assume the problem was a compiler bug. I didn't try other versions in between 7.2.0 and 8.2 to see at which point it started working, but using 8.2 is good enough for me.

Stefan Mach
  • 121
  • 5