Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: unordered floating-point comparison does not raise FE_INVALID

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?

like image 484
Stefan Mach Avatar asked Feb 07 '19 11:02

Stefan Mach


1 Answers

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.

like image 171
Stefan Mach Avatar answered Sep 19 '22 06:09

Stefan Mach