为具有浮点成员的类实现“容忍”`equals`和`hashCode`
我有一个带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值进行比较(例如,参见比较IEEE浮点数和双精度数 )。 但是,我不太确定如何使用此方法实现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尽管彼此相距很远,但是相等。
不幸的是,如果你没有这样的值,你就不能因为传递性而适当地实现等于:x和y可以靠近在一起,y和z可以靠近在一起,但这并不意味着x和z是紧靠在一起。