# Unequal equivalence

## When is a number not a number?

Internet Security Threat Report 2014

### When is a number not a number?

In the world of floating-point numbers there is commonly a notion of a special value that represents something that is *not a number*, NaN for short. A NaN value has some interesting properties: it does not order against any other value, and does not even compare equal to itself. Alas, one problem with having "interesting properties" is that, left to its own devices, a NaN rather messes up the idea of a total ordering that can be used for sorting.

Because Java's type system is not fully object oriented there is a divorce between what can be done with primitive types, such as `double`

and `float`

, and its class-based type system, rooted in `Object`

. Floating-point numbers do not implement the `Comparable`

interface used for ordering objects and it is not possible to hold floating-point numbers directly within a collection. To do this the programmer works instead in terms of the wrapper types, `Float`

and `Double`

, which are proper object types that implement `Comparable`

and wrap their corresponding primitive type. The implementation of `compareTo`

ensures that a NaN will compare equal to another NaN and greater than any other value. As an aside, J2SE 5.0 offers a number of improvements that make working with wrappers less tedious for the programmer, but the underlying model remains unchanged.

C#, by contrast, has a more regular type system, one that incorporates primitive types as first class types in its object system. Wrapper types are not needed, so `double`

and `float`

are synonyms rather than metonyms of the `System.Double`

and `System.Single`

types. They implement the `IComparable`

interface to define a total ordering for floating-point values, including NaN. However, unlike Java they choose the slightly more intuitive ordering of considering all proper values to be greater than a NaN. This policy is also consistent with the idea of treating any object as comparing greater than `null`

(which is, in effect, "not an object").

In C++ ordering is defined, by default, in terms of the < operator rather than via a separate operation granted by an inherited class. This effectively offers the same behaviour as the corresponding operator in C# and Java, which means that because of NaN it doesn't offer a total ordering on all floating-point values.

To understand what this means in practice, consider holding a set of `double`

values. A `std::set`

orders its elements using the defaulted `std::less`

function object type, which corresponds to the < operator in this case, and ensures uniqueness of keys by applying the equivalence outlined earlier — when `!(a < b) && !(b < a)`

evaluates to `true`

then `a`

and `b`

are considered equivalent. If you insert a NaN as the first element in a set then you will never be able to insert anything else, because all values will appear equivalent to NaN. The presence of a NaN pollutes the data set and therefore the container. And, for the same reason, if you insert something else first you will then never be able to insert a NaN!

However, all is not lost. You can impose your own preferred ordering criterion through a function object type, i.e. a class whose instances look like functions because they can be invoked with the function-call operator. The following type imposes an ordering so that a NaN is considered lower than any proper value:

struct total_less { template<typename numeric_type> bool operator()(numeric_type lhs, numeric_type rhs) const { return is_nan(lhs) ? !is_nan(rhs) : lhs < rhs; } };

To use this with a `std::set`

you replace the defaulted `std::less`

comparator with `total_less`

, i.e. declare the type as `std::set<double, total_less>`

rather than as `std::set<double>`

.

The `total_less`

function object type is reasonably straightforward in that it is written in terms of a simple helper, `is_nan`

, and the ordering option is made explicit. Because of what can only be considered an oversight (OK, a cock-up) in the design of the numeric features of C++ standard library, you can use `std::numeric_limits`

to determine whether or not a numeric type has a NaN value, and what it is, but you cannot actually test a value to see whether or not it is a NaN — remember that NaN does not compare equal to itself, so you can't use == to check! However, assuming that infinity compares reflexively, we can take advantage of that very property to define our own predicate:

template<typename numeric_type> bool is_nan(numeric_type value) { return !(value == value); }

This is generic and works for any numeric type, so consequently total_less will also work for any numeric type. ®

This article originally appeared in Application Development Advisor.

Kevlin Henney is an independent software development consultant and trainer. He can be reached at http://www.curbralan.com.