我有一个float
字段的课程。例如:
public class MultipleFields {
final int count;
final float floatValue;
public MultipleFields(int count, float floatValue) {
this.count = count;
this.floatValue = floatValue;
}
}
我需要能够按值比较实例。现在我该如何正确实施equals
& hashCode
?
实施equals
和hashCode
的常用方法是仅考虑所有字段。例如。 Eclipse将生成以下equals
:
public boolean equals(Object obj) {
// irrelevant type checks removed
....
MultipleFields other = (MultipleFields) obj;
if (count != other.count)
return false;
if (Float.floatToIntBits(floatValue) != Float.floatToIntBits(other.floatValue))
return false;
return true;
}
(以及类似hashCode
,基本上计算count* 31 + Float.floatToIntBits(floatValue)
)。
这个问题是我的FP值受到舍入错误的影响(它们可能来自用户输入,来自数据库等)。所以我需要一个“宽容”的比较。
常见的解决方案是使用epsilon值进行比较(参见例如Comparing IEEE floats and doubles for equality)。但是,我不太确定如何使用此方法实现equals
,并且仍然有hashCode
与equals
一致。
我的想法是定义用于比较的有效位数,然后始终舍入到equals
和hashCode
中的该位数:
long comparisonFloatValue = Math.round(floatValue* (Math.pow(10, RELEVANT_DIGITS)));
然后,如果我将floatValue
的所有用途替换为comparisonFloatValue
和equals
中的hashCode
,我应该进行“宽容”比较,这与{{1}一致}}
答案 0 :(得分:10)
它的一大问题是两个浮点值仍然可以非常接近,但仍然比较不相等。基本上你将浮点值的范围划分为桶 - 两个值可以非常接近,而不是在同一个桶中。想象一下你使用两个有效数字,应用截断来获得桶,例如......然后11.999999和12.000001将是不相等的,但12.000001和12.9999999尽管彼此相距很远但是相等。
不幸的是,如果你不这样的桶值,你就不能因为传递性而适当地实现等于:x和y可能在一起,y和z可能在一起,但是这并不意味着x和z靠得很近。