Search code examples
cfloating-pointllvmllvm-ircomparison-operators

Unordered floating point comparisons in C


The default floating point comparisons (e.g., 3.0 < 5.0) in C are ordered, i.e., the produce false if one of the argument is NaN. However, compilers and processors also have unordered comparisons. For example, in LLVM IR the fcmp instruction both has ordered and unordered variants. C99 has some functions to test for NaN. However, apart from that I did not find other unordered comparison operations. Are there any GNU extensions (or other standard library functions) that offer unordered floating point comparisons?

So far, I only could implement them by checking for the opposite condition. For example, to implement an unordered a >= b comparison, I instead wrote an ordered !(a < b) that LLVM eventually simplifies to an unordered comparison fcmp uge double %1, %2.


Solution

  • However, apart from that I did not find other unordered comparison operations. Are there any GNU extensions (or other standard library functions) that offer unordered floating point comparisons?

    As @user2357112 observed in comments, "unordered floating-point comparisons" aren't a thing. The term doesn't even make sense. What you seem to want to evaluate are predicates of the form "x is less than y or the two are unordered".

    Conforming C implementations are not at liberty to add operators, even as extensions. They can, in principle, define additional meanings for existing operators, but I don't know any implementation that provides the specific operations you are looking for that way. As you've already discovered, it's pretty trivial to use C's existing operators for the purpose:

    So far, I only could implement them by checking for the opposite condition. For example, to implement an unordered a >= b comparison, I instead wrote an ordered !(a < b)

    Update: The problem with that is that these comparisons will raise a floating-point exception when one of the operands is NaN (and FP exceptions are not disabled). But you're in luck! Since C99, there are standard macros implementing the comparisons you seek. These are guaranteed to evaluate their arguments only once, and they do not raise floating-point exceptions.

    And, of course, if you want to be able to express more clearly in your code that you are explicitly accommodating NaNs, then you could always write macros for it:

    #define GE_OR_UNORDERED(x, y) (!((x) < (y)))
    
    // ...
    
    if (GE_OR_UNORDERED(a, b)) // ...
    

    Note also that all of this relies heavily on the implementation details. Although C recognizes the possibility that real types can accommodate values, such as NaNs, that do not represent floating-point numbers, it does not require them to do so, nor does it define the behavior of relational or arithmetic operations on such values. Though most implementations these days use IEEE-754 floating point formats and operations, they are not required to do so, and historically, some have not.