Story about differences in software implementations of simple mathematical operations answering the question: “Which of two floating-point values are greater” (or lower).
The float-related implementations of Min and Max are different and in most cases their behavior is not conforming to
IEEE-754–2008 standard (IEEE Standard for Binary Floating-Point Arithmetic).
Consider the following example of naïve generic Max JavaScript implementation:
function Max(a, b) {
if(a > b) {
return a;
} else {
return b;
}
}This implementation isn’t correct in many ways:
- It cannot handle -0 +0 cases (+0 should be greater than -0);
- It doesn’t handles input and number of arguments according to JavaScript specification (-Infinity / +Infinity cases)
And most interesting:
- It cannot handle NaN value correctly (Not-a-Number)

But what is the correct way of handling NaN situation, when a is NaN or b is NaN, or both a and b is NaN. As soon as wee use floating-point numbers we can find citations of IEEE standard and then we will find definitions of minNum and maxNum operations,
which prefer numbers over NaN values, so Max(NaN, number) = Max(number, NaN) = number.
But there are not so many modern IEEE-compatible implementations.
IEEE 754–2008 compatible NaN handling libraries,
where Max(NaN, number) = Max(number, NaN) = number:
C language, since C99 http://en.cppreference.com/w/c/numeric/math/fmax
IEEE 754–2008 incompatible NaN handling libraries,
where Max(NaN, number) = Max(number, NaN) = NaN:
- ECMAScript,
specification http://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2.11 and V8 implementation https://github.com/v8/v8/blob/cd81dd6d740ff82a1abbc68615e8769bd467f91e/src/js/math.js#L77 - .NET (C#, F# and others using Math module, max operator for F#)
https://github.com/dotnet/coreclr/blob/bc146608854d1db9cdbcc0b08029a87754e12b49/src/mscorlib/src/System/Math.cs#L381
Examples of libraries throwing exceptions in case of NaN arguments:
- Ruby (there are max/min methods defined on Enumerable, no standard Max/Min implementations),
will throw “comparison of Float with NaN failed”. But NaN class is still float. Older version of ruby interpreter can throw “comparison of Float with Float failed” exception.
Non-commutative behavior
where Max(number, NaN) isn’t equal to Max(NaN, number)
Swift, Haskell, OCaml
Workarounds available.
Conclusion
It seems that most of the time we should ensure that all of arguments of Min/Max functions are not NaNs, because results can be spoiled by other argument depending on Min/Max implementation.
IEEE standard defines standard behavior, but most of the time in modern languages you will see another behavior.
Why?
- It seems that is because there are no other way of getting error source in result, except exception. And exceptions are considered slow;
- Engineers are making standard libraries by looking at other standard libraries implementations;
- Standard pdf itself isn’t available for free.
- Generic one-for-all implementation looks attractive.
- This is a corner case which is not important most of the time for developers. We should just sit and wait until the problem strikes.
p.s. There is also (± Infinity, NaN) corner case.
Although Standard entries about float operations are available, it’s better for you to read [your_favorite_programming_language] language specification first.

Originally posted on Medium: https://medium.com/@nettsundere/the-implementation-of-min-and-max-operations-for-floating-point-types-80d3616c084d