2014-09-01 74 views
0

我希望printn方法給我「Asterix」和「Oberlix」,因爲3/4與6/8相同。正確執行equals() - 分數的方法

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))); 

所以這是我是如何實現的等號方法:

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; 
} 

很顯然,我做錯了什麼事,因爲這不工作,我的打印方法返回「空」。我的想法是,如果我將這兩個分數的分子和分母分開,結果必須相等,如果分數相等(3/4與6/8相同)。

對不起,我猜這個錯誤肯定是顯而易見的,但我找不到它。

+5

首先權力的有限數量的總和近似,你需要重寫和實現'基於散列的集合hashCode'。其次,我強烈建議你用'Map'使用通用參數化。 – Mena 2014-09-01 12:19:06

+1

對於初學者來說,由於舍入錯誤,您無法可靠地使用相等性來比較浮點數。 – chrylis 2014-09-01 12:19:07

+0

永遠不要使用具有浮點值的'=='... – ortis 2014-09-01 12:21:16

回答

0

你不應該把==加倍,因爲System.out.println(0.1+0.1+0.1)並不總是0.3(對我來說,它輸出0.30000000000000004)。從Double使用equalscompare方法。

因爲你是存儲在您的Fraction類分子和denumenator,你應該在你的equals方法使用足夠接近條件使用自定義小量:

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; 
} 

此外,您將需要重寫hashCode類別中的方法Fraction以便使用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. 


} 
+1

這並不能解決他將這個值作爲HashMap中的一個鍵的問題。試着想出一個包含一個epsilon的'hashCode'的實現,我會贊成。 – 2014-09-01 12:32:51

+0

這個答案在幾點上是誤導和錯誤的。比較兩個分數OP在問題中顯示的方式將始終使用'=='(假設合理的分數值)。 – Keppil 2014-09-01 12:52:26

+0

@Keppil這真的很有趣。你能解釋一下爲什麼在這種情況下使用'=='可以嗎?什麼是「合理的小數值」 – ortis 2014-09-01 12:55:08

1

對於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,你可以用歐幾里德算法簡化分數,然後異或分子和分母的哈希碼。

0

作爲上面的帖子,解決方法是使用「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(); 
    } 

希望這有助於!

+0

無視您將BigDecimal部分中的小數部分丟掉,這可能是該類被稱爲'Fraction'時的一個非常重要的部分:爲什麼要將BigDecimal轉換爲Double對象,然後獲取該對象的hashCode,當'BigDecimal'已經有一個你可以直接調用的方法'hashCode'的實現? – 2014-09-01 13:49:28

+0

BigDecimal不使用與Double相同的hashCode。新Double(6/8)與新Double(3/4)具有相同的hashCode。所以,因爲我只使用Double hashCode()。 – KnusperPudding 2014-09-01 14:31:10

+0

看到其他答案會使實際問題清楚。是的,我搞砸了,對此抱歉。 – KnusperPudding 2014-09-16 08:15:45

2

你可以爲做等於

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

但更好的是要規範的分數。 在等於或在構造函數中標準化分數: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

+0

我可以爲什麼* 31? – Goldi 2014-09-01 14:20:56

+0

涉及到的兩個值必須組合形成一個獨立的值。不使用2的冪混合的東西多一點。素數通常用於乘法。對於文本,經常看到31,因爲大概有26個ASCII字母。但實際上它完全不相關。 – 2014-09-01 16:23:15