Java 实施;“宽容”`等于`&`具有浮点成员的类的hashCode`

Java 实施;“宽容”`等于`&`具有浮点成员的类的hashCode`,java,floating-point,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; } } 我需要能够通过值比较实例。现在我如何正确地实现equals&h

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

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

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

}
我需要能够通过值比较实例。现在我如何正确地实现
equals
&
hashCode

<> >实现<代码>等于和 HASCODE 只是考虑所有字段。例如,Eclipse将生成以下
等于

  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值可能会出现舍入错误(它们可能来自用户输入、DB等)。所以我需要一个“宽容”的比较

常用的解决方案是使用ε值进行比较(参见示例)。但是,我不太确定如何使用此方法实现
equals
,并且仍然有一个与
equals
一致的
hashCode

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

long comparisonFloatValue = Math.round(floatValue* (Math.pow(10, RELEVANT_DIGITS)));
然后,如果我在
equals
hashCode
中将
floatValue
的所有用法替换为
comparisonFloatValue
中的
comparisonFloatValue
,我应该会得到一个与
hashCode
一致的“宽容”比较

  • 这样行吗
  • 你认为这种方法有什么问题吗
  • 有更好的方法吗?这似乎相当复杂

最大的问题是,两个浮点值可能仍然非常接近,但比较起来仍然不相等。基本上,您将浮点值的范围划分为多个存储桶,两个值可能非常接近,而不在同一个存储桶中。假设您使用了两个有效数字,应用截断来获取bucket,例如。。。那么11.9999999和12.000001将是不相等的,但是12.000001和12.9999999将是相等的,尽管它们彼此之间的距离要远得多


不幸的是,如果你不这样存储值,你就不能适当地实现equals,因为传递性:x和y可能很接近,y和z可能很接近,但这并不意味着x和z靠得很近。

你考虑过不使用浮点而改为定点表示吗?@Karl:是的,很好,是的,我考虑过。问题是DB将值保存为FP(这很难更改,因为它不在我们的控制之下),因此我必须在从DB读取时进行取整。我不想这样做,因为我觉得在内部一致地使用FP更好,并且只在输出上进行舍入。哎呀,刚才注意到我使用了^运算符。当然,我指的是指数运算,而不是二进制运算符。已修复为使用
Math.pow
。抱歉,我的comparisonFloatValue计算不正确(我认为Java使用
^
进行求幂:-()。编辑了我的答案。像这样,0.999999999999999和1.0000000001应该比较相等,除非您将相关的_数字设置为大于9左右。当然,您的观点仍然有效:在我的实现中,如果两个FP值落在不同的存储桶中,则它们将被视为不同的值,而任意接近的FP数可能会发生这种情况r、 所以这不会产生一个“宽容的比较”:-(@sleske:Java不使用^进行求幂-这是XOR。使用Math.pow进行求幂。我的示例可能很不幸-我会编辑。但是,是的,您基本上需要解决您的需求:)实际上,这将是一个有效的“宽容的比较”如果FP值的有效位数小于
相关_位数
(即它们实际上是小数点后小于
相关_位数
的定点数字),幸运的是在我的应用程序中就是这样。对于任意FP值,这将不起作用(我相信在这种情况下没有解决方案)事实上,我最后的评论有点傻。当然,一个“宽容”的比较认为x,y是相等的,如果
abs(x-y)