Two complex numbers with real/imaginary parts 0.0d but different signs compare as equal numbers. This is according to their mathematical value; the comparison is done via
return (real == c.real) && (imaginary == c.imaginary);
Unfortunately, two Double values do NOT compare as equal in that case, so real.equals(c.real) would return false if the signs differ.
This becomes a problem because for the hashCode, MathUtils.hash is used on the real and imaginary parts, which in turn uses Double.hash.
This violates the contract on equals/hashCode, so Complex numbers cannot be used in a hashtable or similar data structure:
Complex c1 = new Complex(0.0, 0.0);
Complex c2 = new Complex(0.0, -0.0);
// Checks the contract: equals-hashcode on c1 and c2
assertTrue("Contract failed: equals-hashcode on c1 and c2", c1.equals(c2) ? c1.hashCode() == c2.hashCode() : true);