This means that in Haskell, for example, you cannot really rely on the Eq class representing an equivalence relation. Code relying on the fact that x == x should be true for all x could not work as expected for floating point numbers.
I don't know if this has any practical ramifications in real code, but it certainly makes things less elegant and more complex than they have to be.
However, you should be able to examine two NaNs and declare them "equivalent" (for certain definitions of equivalence) by intelligently examining the bits based on the hardware that you're running the program on. In the case of a binary Nan  that would entail checking that the exponential fields are both entirely high (eg 0x8 == (a.exponent & b.exponent), assuming a standard 8 bit exponent) and that the mantissas are nonzero (eg a.mantissa && b.mantissa).
: "Binary format NaNs are represented with the exponential field filled with ones (like infinity values), and some non-zero number in the significand (to make them distinct from infinity values)." --http://en.wikipedia.org/wiki/NaN
float a = 1.0;
float b = 1000.0;
for (int i = 0; i < 1000000; ++i)
b *= b;
float a = 0.0;
float b = 10000.0;
for (int i = 0; i < 100000000; ++i)
b *= b;
and what happens when you go beyond 24 bits? since it's a float no error or warning will be thrown, but now equivalence won't work for numbers that are easily stored by an int.
Where did I say I'd use floating point numbers for integer math? Yes, let's move the conversation to a direction it never existed so that you can pretend you were right.
What do you mean by
algorithms that are more reliably written not to contain any empty intervals are two examples.
> What do you mean by
I mean exactly that sort of thing. Algorithms that, for example, divide a line into intervals, where empty intervals are not needed, or desired, and are generally risky with respect to the probability of having a correct implementation. An example of this would be computations of the area of a union of rectangles. You might make a segment tree -- and avoid having degenerate rectangles in your segment tree.
A null (and NaN) is like an unknown. One can't compare unknowns because they are exactly that, unknown.
Let's construct a language that on division on zero returns unknowns.
a = 5 / 0;
b = 10 / 0;
I wish all languages would have nullability like SQL does. Where a great care has to be given to deal with nullable data, lest nulls nullify everything.
The answer is that 5 / 0 is Infinity and (5 / 0) == (5 / 0), so it's all good :). Now, 0 / 0 is NaN and (0 / 0) != (0 / 0).
I guess one option would be to just declare that all NaNs are equal--I'm pretty sure that's how bottoms work in Haskell, and it seems that NaN is essentially a floating-point version of bottom.
This is somewhat simpler--as long as either argument to (==) is NaN the answer is False. However, you still have to figure out that at least one bit pattern corresponds to NaN. If you want them to be equal, you would have to figure out that both are NaN. This is certainly a little more difficult, but I think it isn't much worse than the current scenario.