The problem starts here:
(x == x) is true, except when (x == NaN)
Some people advocate that this should not be so, i.e.
but IEEE574 has chosen the former. And Java primitive "double" conforms to this.
I don't understand the rationale of having decided that "Double" should behave differently than "double", but this is beyond our reach anyway . But, if you'd have to define "equals" for "Double" wouldn't you check the equality of the "double" returned by "doubleValue()"? In the example reported by Luc, this is done similarly and two complex NaNs won't be equal.
What bothers me, slightly , is that CM is not consistent with itself: A "Complex" instance is an abstraction/approximation of a complex number, in the same way that a "double" is an abstraction/approximation of a real number. So why would you consider that
[...] it makes sense to lump all instances with NaN parts into one equivalence class modulo equals.
and at the same time that CM should also follow IEEE754 for "double" (cf. "MathUtils.equals"), which is the opposite of the previous statement?
 Personally, I never had to use NaN beyond being a signal that there was a bug in my code.