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 ofisless(x, y)
is always equal to(x) < (y)
; however, unlike(x) < (y)
,isless(x, y)
does not raise the "invalid" floating-point exception whenx
andy
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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With