Le mer. 8 avr. 2020 à 14:26, Alex Herbert <alex.d.herb...@gmail.com> a écrit :
>
>
> On 08/04/2020 00:36, Gilles Sadowski wrote:
> > 2020-04-07 23:01 UTC+02:00, Alex Herbert <alex.d.herb...@gmail.com>:
> >>
> >>> On 7 Apr 2020, at 17:47, Gilles Sadowski <gillese...@gmail.com> wrote:
> >>>
> >>> Le mar. 7 avr. 2020 à 14:54, Alex Herbert <alex.d.herb...@gmail.com
> >>> <mailto:alex.d.herb...@gmail.com>> a écrit :
> >>>> On 07/04/2020 13:43, Alex Herbert wrote:
> >>>>> Fraction
> >>>>>
> >>>>> I also did a big arrangement of Fraction and BigFraction.
> >>> Thanks.
> >>>
> >>>> I noticed that hashCode is using some variant of the format used in
> >>>> Arrays.hashCode(...)
> >>>>
> >>>> I wondered if we should standardise on returning a value as if computed
> >>>> using e.g. Arrays.hashCode(new int[]{numerator, denominator}) as was
> >>>> done for Complex with its two parts.
> >>>>
> >>>> This would change in Fraction:
> >>>>
> >>>> public int hashCode() {
> >>>>      return 37 * (37 * 17 + numerator) + denominator;
> >>>> }
> >>> Strange that the constant 37 * 17 was not pre-computed. ;-)
> >> Yes. Weird. It was like that in CM 3.6.1.
> >>
> >> Not knowing if one is better than the other
> > The "17" seems to come from "Effective Java" (where J. Bloch says
> > that it is arbitrary apart from being nonzero, so "1" is fine too I guess).
> >
> >> (do you just pick a small prime
> >> for the factor?) I’d just shift it to use the same method as 
> >> Arrays.hashCode
> >> for consistency with Complex.
> > Fine.
> > The factor is indeed "31" in Effective Java, saying that it must be
> > odd, and that a prime is a traditional choice.
>
> hashCode was actually broken so it needed an update.
>
> These
>
> -1 / 3
>
> 1 / -3
>
> did not have the same hashCode even though they are equal. This violates
> the Object.hashCode contract.

Oops.
I overlooked that when we decided to allow both internal representations.

>
> There were two options:
>
> 1. Create the hashCode using: |numerator|, |denominator|
>
> 2. Create the hashCode using: signum, |numerator|, |denominator|
>
> I went for option 2. Thus 1/3 and -1/3 have different hash codes.
>
> The hash code computation currently matches (for Fraction f):
>
>      Arrays.hashCode(new int[] {f.signum(),
> Math.abs(f.getNumerator()),
> Math.abs(f.getDenominator())});
>
> The computation is done inline without delegating to Arrays.

I'd rather keep it simple and delegate to the JDK method above.
Indeed, is there any reasonable use-case for using a fraction
as hash map key?
If not, IMO, better make the code self-documenting.

> It could be changed to:
>
> f.signum() * Arrays.hashCode(new int[] {Math.abs(f.getNumerator()),
> Math.abs(f.getDenominator())});

-0
Same rationale as above.

> The later would remove a single integer addition operation from the
> computation so probably no speed difference.

Zero difference if "hashCode()" is never called. ;-)

Gilles

> Any opinions on this? Given the signum is a 3-state flag it may be
> better moved outside the computation. This would mean that a fraction
> with the value 0 has the hashCode 0.

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

Reply via email to