commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Gilles <gil...@harfang.homelinux.org>
Subject Re: [math] Issue with equals/hashCode on Complex/Dfp instances
Date Fri, 18 Apr 2014 10:57:51 GMT
On Tue, 15 Apr 2014 09:52:08 -0700, Phil Steitz wrote:
> On 4/15/14, 5:19 AM, Gilles wrote:
>> 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".
>
> Thanks.  I get that now.
>>
>> 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?
>
> I don't think having equal instances hashing to different values is
> acceptable.  We have to do something to fix that.
>>
>> 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").
>
> I like the idea of imitating the way Double works for equals.
>

I've uploaded[1] a tentative patch that
  1. changes the behaviour of "equals(Object)", so that it has it has 
the
     same semantics as "Double",
  2. adds static methods to test floating-point equality of instances 
(by
     delegating to the corresponding methods in class "Precision").


Regards,
Gilles

[1] https://issues.apache.org/jira/browse/MATH-1118


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Mime
View raw message