正确执行equals() - 分数的方法
我希望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相同)。
对不起,我猜这个错误肯定是显而易见的,但我找不到它。
你不应该把==
加倍,因为System.out.println(0.1+0.1+0.1)
并不总是0.3
(对我来说,它输出0.30000000000000004
)。从Double
使用equals
或compare
方法。
因为你是存储在您的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.
}
对于HashMap
工作,你必须实现equals
和hashCode
。我只提供部分答案,因为我没有太多时间,所以只有equals
。
要比较两个分数而不求助于double
s,只需做一些简单的算术。你有两个分数,a/b
和c/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
,你可以用欧几里德算法简化分数,然后异或分子和分母的哈希码。
作为上面的帖子,解决方法是使用“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();
}
希望这有助于!
无视您将BigDecimal部分中的小数部分丢掉,这可能是该类被称为'Fraction'时的一个非常重要的部分:为什么要将BigDecimal转换为Double对象,然后获取该对象的hashCode,当'BigDecimal'已经有一个你可以直接调用的方法'hashCode'的实现? – 2014-09-01 13:49:28
BigDecimal不使用与Double相同的hashCode。新Double(6/8)与新Double(3/4)具有相同的hashCode。所以,因为我只使用Double hashCode()。 – KnusperPudding 2014-09-01 14:31:10
看到其他答案会使实际问题清楚。是的,我搞砸了,对此抱歉。 – KnusperPudding 2014-09-16 08:15:45
你可以为做等于
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
我可以为什么* 31? – Goldi 2014-09-01 14:20:56
涉及到的两个值必须组合形成一个独立的值。不使用2的幂混合的东西多一点。素数通常用于乘法。对于文本,经常看到31,因为大概有26个ASCII字母。但实际上它完全不相关。 – 2014-09-01 16:23:15
首先权力的有限数量的总和近似,你需要重写和实现'基于散列的集合hashCode'。其次,我强烈建议你用'Map'使用通用参数化。 – Mena 2014-09-01 12:19:06
对于初学者来说,由于舍入错误,您无法可靠地使用相等性来比较浮点数。 – chrylis 2014-09-01 12:19:07
永远不要使用具有浮点值的'=='... – ortis 2014-09-01 12:21:16