2014-09-01 47 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