实施“宽容” `equals'&具有浮点成员的类的`hashCode` [英] Implement "tolerant" `equals` & `hashCode` for a class with floating point members

查看:151
本文介绍了实施“宽容” `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



执行的常用方式等于 hashCode 就是考虑所有字段。例如。 Eclipse将生成下面的 equals
$ b

  public boolean equals(Object obj ){
//不相关的类型检查被删除
....
MultipleFields other =(MultipleFields)obj;
if(count!= other.count)
return false;
if(Float.floatToIntBits(floatValue)!= Float.floatToIntBits(other.floatValue))
return false;
返回true;

$ / code $ / $ p

$(和一个类似的$ code> hashCode
,从本质上计算 count * 31 + Float.floatToIntBits(floatValue))。

这个问题是我的FP值受到舍入误差(他们可能来自用户输入,来自数据库等)。所以我需要一个容忍的比较。

常见的解决方案是使用epsilon值进行比较(请参阅比较IEEE浮游物和双等号)。但是,我不太确定如何使用这个方法来实现 equals ,并且仍然有一个 hashCode 符合等于

我的想法是定义用于比较的有效数字的数量,然后总是以等于 hashCode

<$ p $> long compareFloatValue = Math.round(floatValue *(Math.pow(10,RELEVANT_DIGITS)));

然后,如果我替换 floatValue comparisonFloatValue 等于 hashCode ,我应该得到宽容的比较,这与 hashCode




  • 是一致的吗?

  • 您是否看到这种方法存在任何问题?

  • 有没有更好的方法来做到这一点?这似乎相当复杂。

解决方案

尽管非常接近,但仍然不相等。基本上,你将浮点值的范围分成桶,两个值可以非常接近,而不在同一个桶中。想象一下,你使用了两位有效数字,应用截断来获得水桶,例如...然后11.999999和12.000001将是不相等的,但12.000001和12.9999999将是相等的,尽管彼此之间的距离更远。


$ b

不幸的是,如果不是这样的桶值,那么由于传递性,你不能适当地实现equals:x和y可能靠近在一起,y和z可能会靠近在一起,但这并不意味着x和z在一起。


I have a class with a float field. For example:

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

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

}

I need to be able to compare instances by value. Now how do I properly implement equals & hashCode?

The usual way to implement equals and hashCode is to just consider all fields. E.g. Eclipse will generate the following 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;
  }

(and a similar hashCode, that essentially computes count* 31 + Float.floatToIntBits(floatValue)).

The problem with this is that my FP values are subject to rounding errors (they may come from user input, from a DB, etc.). So I need a "tolerant" comparison.

The common solution is to compare using an epsilon value (see e.g. Comparing IEEE floats and doubles for equality). However, I'm not quite certain how I can implement equals using this method, and still have a hashCode that is consisten with equals.

My idea is to define the number of significant digits for comparison, then always round to that number of digits in both equals and hashCode:

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

Then if I replace all uses of floatValue with comparisonFloatValue in equals and hashCode, I should get a "tolerant" comparison, which is consistent with hashCode.

  • Will this work?
  • Do you see any problems with this approach?
  • Is there a better way to do this? It seems rather complicated.

解决方案

The big problem with it is that two float values could still be very close together but still compare unequal. Basically you're dividing the range of floating point values into buckets - and two values could be very close together without being in the same bucket. Imagine you were using two significant digits, applying truncation to obtain the bucket, for example... then 11.999999 and 12.000001 would be unequal, but 12.000001 and 12.9999999 would be equal despite being much further apart from each other.

Unfortunately, if you don't bucket values like this, you can't implement equals appropriately because of transitivity: x and y may be close together, y and z may be close together, but that doesn't mean that x and z are close together.

这篇关于实施“宽容” `equals'&amp;具有浮点成员的类的`hashCode`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆