On Tue, 15 Apr 2014 08:03:51 +0900, Cyrille Artho wrote:
Dear all,
Java's default contract (in Object) states that two objects with
equal data should return the same hashCode. In other words, if
a.equals(b), their return value of hashCode() must be the same.
Unfortunately, with Double values, new Double(0.0d).equals(new
Double(-0.0d)) is false. This is because their internal
representation
differs. Java's built-in Double thus returns a different hashCode for
0.0d and -0.0d.
However, Apache's math library uses a mathematical comparison for
Complex/Dfp (perhaps also others), where 0.0d == -0.0d. This breaks
the contract, and thus causes problems when Complex or Dfp instances
are used in containers such as HashMap, HashSet, etc. See the bug
report for more details and test cases:
https://issues.apache.org/jira/browse/MATH-1118
It is not quite clear how this should be fixed. Gilles posted a patch
that uses Java's equals to perform the comparison. This fixes the
behavior w.r.t. the contract but may surprise people who expect a
mathematical comparison.
Another possible fix (without a tentative patch at this time) would
be to change hashCode:
public int hashCode() {
if (imaginary == 0.0d && real == 0.0d) {
return ZERO.hashCode();
}
...
and similar for Dfp.
This fixes the issue for zero values. However, there may be issues
with normalized vs. unnormalized floating point values with the same
(mathematical) value but different internal representations, where
this kind of fix cannot be used. I'm not familiar enough with various
floating point implementations to know if Java always normalizes the
values before using them in a statement like hashCode().
Therefore, the suggestion above is mathematically nice for +/- 0.0d,
but otherwise much less safe than Gilles' patch.
Any comments? Probably best post them on JIRA:
https://issues.apache.org/jira/browse/MATH-1118
IIUC, fixing the "hashCode" method as above would not solve the problem
since it deals only with "0" whereas the unit test fails for "-i".
Do we agree that we first have to decide whether "Complex" should
behave
as "Double"?
If the answer is "no" (as is the case now), shouldn't we document that
"hash tables will not operate properly" (cf. Javadoc for "Double")?
And is this behaviour acceptable?
One possibility is to have the "equals(Complex)" behave according to
the JDK semantics, and add a static method "equals(Complex, Complex)"
that would implement mathematical comparison (where "-0" == "0").
Regards,
Gilles
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org