Is !NaN not a NaN?

Viewed 469

I came across this code that spews a warning with gcc:

float f;
// Calculate a value for f
if (!f == 0.0)
{
    // Handle it being non-zero
}

It was probably just a typo by another team member, and examining the code what was really meant was:

if (f != 0.0)
// OR
if (!(f == 0.0))

I've corrected the code, but I was just wondering what would !NaN evaluate to. We use the f value inside the if, so we don't want NaNs getting past the check.

3 Answers

If you want to avoid a NaN inside if, you can use the function

bool isnan( float arg );

to perform a check.

From the reference of the function:

NaN values never compare equal to themselves or to other NaN values. Copying a NaN is not required, by IEEE-754, to preserve its bit representation (sign and payload), though most implementation do.

Another way to test if a floating-point value is NaN is to compare it with itself:

bool is_nan(double x) { return x != x; } 

The C++ draft (N4713) states:

8.5.2.1 Unary operators [expr.unary.op]
...
9. The operand of the logical negation operator ! is contextually converted to bool (Clause 7); its value is true if the converted operand is false and false otherwise. The type of the result is bool.

7.14 Boolean conversions [conv.bool]
1. A prvalue of arithmetic, unscoped enumeration, pointer, or pointer-to-member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.

Conclusion: As NaN is contextually converted as true in the expression !NaN, !NaN is false and thus not a NaN.

See https://en.cppreference.com/w/cpp/language/implicit_conversion

A prvalue of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type bool.

The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true

Therefore !f == 0.0 is equivalent to !(f != 0.0) == 0.0 or (f == 0.0) == false or f != 0.0

Simply use

if (!isnan(f)&& !f == 0.0)
    {
        cout<<"Filtered NaN values"<<endl;

    }
Related