簡體   English   中英

分數的equals()-Method的正確實現

[英]Correct implementation of the equals()-Method for fractions

我希望printn方法給我“ Asterix”和“ Oberlix”,因為3/4與6/8相同。

HashMap hm = new HashMap();
hm.put(new Fraction(3, 4), "Asterix");
hm.put(new Fraction(19, 12), "Oberlix");
System.out.println(hm.get(new Fraction(6, 8)));
System.out.println(hm.get(new Fraction(38, 24)));

這就是我實現equals-Method的方式:

public boolean equals(Object obj) {
    boolean isEqual = false;

    if(obj instanceof Fraction) {
        Fraction frac = (Fraction) obj;

        if(((double) this.numerator / (double) this.denumerator) == ((double) frac.numerator / (double) frac.denumerator)) {
            isEqual = true;
        }
    }
    return isEqual;
}

顯然我做錯了,因為那不起作用,並且我的打印方法返回“ null”。 我的想法是,如果我分別使用兩個分數的分子和分子,那么如果分數相等(3/4與6/8相同),則結果必須相等。

抱歉,我想這個錯誤一定很明顯,但我找不到。

你可以做到平等

return denominator * other.numerator == numerator * other.denominator;

但更好的方法是進行典范分數。 在equals或構造函數中均對分數進行歸一化:6/8變為3/4。

public class Fraction implements Number {
    private final int numerator;
    private final int denominator;

    public Fraction(int numerator, int denominator) {
        if (denominator < 0) {
            denominator = -denominator;
            numberator = -numerator;
        }
        int commonFactor = gcd(numerator, denominator);
        this.numerator = numerator / commonFactor;
        this.denominator = denominator / commonFactor;
    }

    @Override
    public boolean equals(Object other) {
        ...
        Fraction otherFraction = ...
        return denominator == otherFraction.denominator
            && numerator == otherFraction.numerator;
    }

    private static int gcd(int x, int y) {
        x = Math.abs(x);
        y = Math.abs(y);
        ...
        while (x != y) {
            if (x > y) {
                x -= y;
            } else {
                y -= x;
            }
        }
        return x;
    }

什么更好? 您現在可以創建一個hashCode:

@Override
int hashCode() {
    return denominator * 31 + numerator;
}

浮點數是有限數量的2的冪的近似和。

為了使HashMap正常工作,您需要同時實現equalshashCode 我將提供部分答案,僅適用於equals ,因為我沒有太多時間。

要比較兩個分數而不求助於double s,只需執行一些簡單的算法即可。 您有兩個分數a/bc/d 假設分母為非零:

a/b == c/d
  (multiply left and right by b)
a == c/d*b
  (multiply left and right by d)
a*d == c*b

所以:

public boolean equals(Object obj) {
  if (!(obj instanceof Fraction)) {
    return false;
  }
  Fraction other = (Fraction) obj;
  return this.numerator * other.denominator == other.numerator * this.denominator;
}

請注意,這不適用於很大的分數; 他們會溢出。 如果您想正確處理這些內容,請投放較長時間。


為了實現hashCode ,您可以使用Euclidean算法簡化分數,然后對分子和分母的哈希碼進行異或運算。

您永遠不要將==與double進行比較,因為System.out.println(0.1+0.1+0.1)並不總是0.3 (對我來說,它輸出0.30000000000000004 )。 使用Double equalscompare方法。

因為在類Fraction同時存儲了分子和減法器,所以您應該在equals方法中使用足夠接近的條件和自定義epsilon:

public boolean equals(Object obj) {
    boolean isEqual = false;

    if(obj instanceof Fraction) {
        Fraction frac = (Fraction) obj;

        if(Math.abs(((double)this.numerator)/this.denumerator) - ((double)frac.numerator)/frac.denumerator) < .00000001/*epsilon*/) {
            isEqual = true;
        }
    }
    return isEqual;
}

同樣,您將需要在類Fraction中重寫hashCode方法,以使用HashMap 由於此equals實現僅取決於一個值(分數的結果),因此可以使用以下方法:

public int hashCode()
{

    return 0;//all Fraction return the same hashCode, which make HashMap call equals each time

    //EDIT: the following is WRONG: assuming eps = 0.1, 299/100 is equals to 300/100 but hashCode will be different (2 and 3).

    //return this.numerator/this.denumerator ;//since those are int (I guess),
    //it will truncate the floating part. So you will just check for the integer part.


}

如上面的帖子所述,解決方案的方法是使用“ hasCode()”而不是equals()。
這是有關如何獲取正確的hashCode的選項:

    @Override
    public int hashCode() {
        // Calculating with double is troublesome sometimes, so i use BigDecimal here
        BigDecimal value = BigDecimal.valueOf(this.numerator).divide(BigDecimal.valueOf(this.denumerator), RoundingMode.HALF_UP);
        // after this, i just return the hashCode i would get, if if my parameter was a simple Double Value:
        return Double.valueOf(value.doubleValue()).hashCode();
    }

希望這可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM