## When Good Code Goes NaN: How mismanaging Java's Unorderable NaN Value led to a bug

I recently encountered a bug which was caused by a NaN value in my Java code. NaN, short for "Not a Number", is a valid value for a float or a double. NaN is a tricky value because (1) it spreads like a virus and (2) it is unorderable.

### NaN is a virus

NaN spreads like a virus because every operations that involves a NaN will result in more NaN.

float f1 = 42f + Float.NaN; // f1 = Float.NaN float f2 = 0.5 * f1; // f2 = Float.NaN

Once a NaN, always a NaN. So if you are not careful, a NaN will spread throughout your program and may cause unexpected bugs.

### The Unorderable Nature of NaN

NaN is unorderable, which means that `x > Float.NaN`

and ```
x <
Float.NaN
```

are both `false`

. Imagine you are a cautious programmer who
uses defensive programming, you put post-condition in your code to
ensure that the value your computing is always within a valid range.

// compute a value if (value < lowLimit || value > highLimit) { throw IllegalArgumentException("Incorrect value " + value + " out of range"); } else { return value; }

You may think you're fine, I certainly did thought that. But you're not!
Since NaN is unorderable, `NaN < lowLimit`

is `false`

and so is ```
NaN >
highLimit
```

, so the exception is not raised and the NaN is returned.
NaN keeps spreading.

### The bug

In my application, a NaN value escaped the post-condition check and was then converted to an int using Math.round.
And what does `Math.round()`

with NaN? It returns 0!

So when the application displayed the result on screen, it appeared as a 0, which in that particular context made no sense.

### Solutions

So what are the solutions? So far I have identified the following:

#### Check the Javadoc

Check the javadoc of the Math functions you are using to find out when you could get a NaN (for example sqrt, log, pow, sin, …) or what they do with NaN (for example round).

#### Use `Float.isNaN()`

Check explicitely for NaN with Float.isNaN() before checking the value.

// compute a value if (Float.isNaN(value) || value < lowLimit || value > highLimit) { throw IllegalArgumentException("Incorrect value " + value + " out of range"); } else { return value; }

#### Use `Float.compare()`

Use Float.compare() whose contract says NaN is equal to itself and greater than Float.POSITIVE_INFINITY.

// compute a value if (Float.compare(value, lowLimit) < 0 || Float.compare(value,highLimit) > 0) { throw IllegalArgumentException("Incorrect value " + value + " out of range"); } else { return value; }

A word of cautions on `Float.compare()`

, make sure to check for the
high limit. For example, if you only checked that the result was
positive you may still let NaN spreads.

// compute a value if (Float.compare(value, 0f) < 0) { // value is > 0 but can be Float.POSITIVE_INFINITY or Float.NaN. throw IllegalArgumentException("Incorrect value " + value + " out of range"); } else { return value; }

### Conclusion

I wish there was a way to raise an exception whenever a NaN creeps in.
Until then, be careful when you are manipulating float, check for NaN
with `Float.isNaN()`

or `Float.compare()`

.

Here is the spec on Java float complete behaviors: https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3