55

I have a float value set to NaN (seen in the Watch Window), but I can't figure out how to detect that in code:

if (fValue == float.NaN) // returns false even though fValue is NaN
{
}
John Feminella
  • 303,634
  • 46
  • 339
  • 357
Anthony Brien
  • 6,106
  • 7
  • 43
  • 56

5 Answers5

111

You want float.IsNaN(...). Comparisons to NaN always return false, no matter what the value of the float is. It's one of the quirks of floating points.

That means you can do this:

if (f1 != f1) { // This conditional will be true if f1 is NaN.

In fact, that's exactly how IsNaN() works.

John Feminella
  • 303,634
  • 46
  • 339
  • 357
37

Try this:

if (float.IsNaN(fValue))
{
}
Jakob Christensen
  • 14,826
  • 2
  • 51
  • 81
15

In performance-critical code float.IsNaN could be too slow because it involves FPU. In that case you can use binary mask check (according to IEEE 754 specification) as follow:

public static unsafe bool IsNaN (float f)
{
    int binary = *(int*)(&f);
    return ((binary & 0x7F800000) == 0x7F800000) && ((binary & 0x007FFFFF) != 0);
}

It is 5 times faster than float.IsNaN. I just wonder why Microsoft did not implement IsNaN in such way. If you'd prefer not using unsafe code you still can use union-like structure:

[StructLayout (LayoutKind.Explicit)]
struct FloatUnion
{
    [FieldOffset (0)]
    public float value;

    [FieldOffset (0)]
    public int binary;
}

public static bool IsNaN (float f)
{
    FloatUnion union = new FloatUnion ();
    union.value = f;

    return ((union.binary & 0x7F800000) == 0x7F800000) && ((union.binary & 0x007FFFFF) != 0);
}

It's still 3 times faster than IsNaN.

Dmitry Fedorkov
  • 4,301
  • 1
  • 21
  • 30
  • 1
    "I just wonder why Microsoft did not implement IsNaN in such way." Because that code is platform-dependent and would break elsewhere. – John Feminella May 21 '12 at 12:32
  • 3
    Floating-point data structure is described in IEEE 754 and is platform-independent. Moreover, checks on infinity are implemented in .NET via binary comparisons e.g. `((*(((int*) &f)) & 0x7fffffff) == 0x7f800000)`. – Dmitry Fedorkov May 23 '12 at 12:01
  • 3
    The floating-point _data structure_ is platform-independent, but endianness isn't. – John Feminella May 23 '12 at 12:12
  • 3
    Is binary comparison really endian-dependent? Byte order in binary mask will be the same as in int value. Anyway, if Microsoft decided to use such check on infinity, they could use the same way for NaN checks. – Dmitry Fedorkov May 23 '12 at 12:41
  • It seems NaN is rarely concerned in performance critical code. Why do you need it? It's generated by 0/0, in most cases it's an exception. – Lenik Aug 09 '12 at 05:32
  • 1
    I've made this investigation when I faced a need to check a large array of floats on NaN's. – Dmitry Fedorkov Aug 10 '12 at 09:15
  • Note that inside WPF, Microsoft uses a similar technique for checking IsNaN on Doubles. The source is commented indicating that this is a perf optimization and that there's an internal work item to switch the framework over to the improved implementation. Here's the link: https://referencesource.microsoft.com/#WindowsBase/Shared/MS/Internal/DoubleUtil.cs,303 – EisenbergEffect Nov 22 '17 at 04:20
  • 3
    This is now how double.IsNaN works: http://referencesource.microsoft.com/#mscorlib/system/double.cs,101 – canton7 Jan 12 '18 at 10:37
8
if(float.isNaN(fValue))
{
}
Jeff Mc
  • 3,723
  • 1
  • 22
  • 27
1
if (fValue.CompareTo(float.NaN) == 0)

Note: I know, the thread is dead.

Tipx
  • 7,367
  • 4
  • 37
  • 59