Search code examples
cnanieee-754

Why does isnan(x) exist if x != x gives the same result?


It is well known that for any variable of floating-point type x != x iff (if and only if) x is NaN (not-a-number). Or inverse version: x == x iff x is not NaN. Then why did WG14 decide to define isnan(x) (math.h) if the same result can be obtained using the natural capabilities of the language? What was the motivation? Better code readability?

Extra question: Are there any functional differences between isnan(x) and x != x?


Solution

  • if the same result can be obtained using natural capabilities of the language?

    C does not specify x == x iff x is not NaN. Many implementations do that though. C does not require adherence to IEEE_754. isnan(x) is well defined.

    Use isnan(x) for portable code.


    C in Representations of types (since C99) has

    Two values (other than NaNs) with the same object representation compare equal, but values that compare equal may have different object representations.

    ... but that does not specify the behavior of comparing 2 NANs.


    When __STDC_IEC_559__ (akin to adherence to IEEE-754) is defined as 1 (something not required by C), then

    "The expression x != x is true if x is a NaN."

    "The expression x == x is false if x is a NaN."

    When __STDC_IEC_559__ is not defined as 1, exercise caution about assuming behavior in the edges of floating point math such as NAN equality.


    [Edit to address some comments]

    C, on the corners of FP math, lack the specifics of IEEE-754. C89 allowed NANs as evidenced by references to IEEE-754, yet lacked isnan(x). There was no "Two values (other than NaNs) with the same object representation compare equal, ..." to guide either. At that time, x==x for NAN was not specified. With C99, rather than break or invalidate prior code, isnan(x) is defined as a clear NAN test. As I see it, x==x remains unspecified for NANs, yet it is commonly results in false. isnan(x) also provides code clarity. Much about C and NAN is fuzzy: round tripping payload sequences, signaling encoding/discernment, NAN availability, ...


    Are there any functional differences between isnan(x) and x != x?

    In addition to the well defined functionality of isnan(x) versus x != x discussed above, some obscure ones:

    • isnan(x) evaluates x once versus twice for x != x. Makes a difference if x was some expression like y++.

    • isnan(x) operates on the sematic type. This makes a difference when "the implementation supports NaNs in the evaluation type but not in the semantic type.". x != x operates on the evaluation type. Research FLT_EVAL_METHOD for more detail.