我有一个带有 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
,并且仍然有一个与 equals
一致的 hashCode
。
我的想法是定义用于比较的有效位数,然后在 equals
和 hashCode
中始终舍入到该位数:
long comparisonFloatValue = Math.round(floatValue* (Math.pow(10, RELEVANT_DIGITS)));
然后,如果我在 equals
和 hashCode
中用 comparisonFloatValue
替换所有对 floatValue
的使用,我应该得到一个“容忍”比较,与hashCode
一致。
- 这行得通吗?
- 您认为这种方法有什么问题吗?
- 有更好的方法吗?看起来比较复杂。
最佳答案
最大的问题是两个浮点值可能仍然非常接近但仍然比较不相等。基本上,您将浮点值的范围划分为桶 - 两个值可能非常接近而不在同一个桶中。假设您正在使用两位有效数字,应用截断来获取存储桶,例如...那么 11.999999 和 12.000001 将不相等,但 12.000001 和 12.9999999 将相等,尽管彼此相距很远。
不幸的是,如果您不像这样存储值,由于传递性,您不能适本地实现 equals:x 和 y 可能靠得很近,y 和 z 可能靠得很近,但是这并不意味着 x 和 z 靠得很近。
关于java - 为具有浮点成员的类实现 "tolerant" `equals` & `hashCode`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4386877/