java - 为具有浮点成员的类实现 "tolerant" `equals` & `hashCode`

标签 java floating-point equals hashcode

我有一个带有 float 字段的类。例如:

public class MultipleFields {
  final int   count;
  final float floatValue;

  public MultipleFields(int count, float floatValue) {
    this.count = count;
    this.floatValue = floatValue;
  }

}

我需要能够按值比较实例。现在我该如何正确实现 equalshashCode

实现equalshashCode 的常用方法是只考虑所有字段。例如。 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

我的想法是定义用于比较的有效位数,然后在 equalshashCode 中始终舍入到该位数:

long comparisonFloatValue = Math.round(floatValue* (Math.pow(10, RELEVANT_DIGITS)));

然后,如果我在 equalshashCode 中用 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/

相关文章:

java - 是否有 Java 实用程序可以对两个对象进行深入比较?

c# - 重写结构中的 Equals 方法

python - 混淆复合Python语句的语法错误

java - 滚动时如何固定 PopupPanel 相对于页面的位置

java - 如何为线程设置名称?

iphone - Objective-C 中类型之间的转换

Haskell 将 Float 转换为 Int

java - Java Servlet 中的 session 等

Java:空值解析 XML 文件

math - 为什么十进制数不能用二进制精确表示?