如何在equals()中有效地使用浮点数?

时间:2014-04-08 08:14:53

标签: java equals

我有以下不可变的HSL类,我用它来表示RGBA颜色计算的颜色和辅助,并且更加精细。

public class HSL {
  protected final float hue;
  protected final float saturation;
  protected final float lightness;

  public HSL(float hue, float saturation, float lightness) {
    this.hue = hue;
    this.saturation = saturation;
    this.lightness = lightness;
  }

  // [snip] Removed some calculation helper functions

  @Override
  public String toString() {
    return "HSL(" + hue + ", " + saturation + ", " + lightness + ")";
  }

  @Override
  public int hashCode() {
    return
        37 * Float.floatToIntBits(hue) +
        37 * Float.floatToIntBits(saturation) +
        37 * Float.floatToIntBits(lightness);
  }

  @Override
  public boolean equals(Object o) {
    if (o == null || !(o instanceof HSL)) {
      return false;
    }

    HSL hsl = (HSL)o;
    // We're only worried about 4 decimal places of accuracy. That's more than the 24b RGB space can represent anyway.
    return
        Math.abs(this.hue - hsl.hue) < 0.0001f &&
        Math.abs(this.lightness - hsl.lightness) < 0.0001f &&
        Math.abs(this.saturation - hsl.saturation) < 0.0001f;
  }
}

虽然我没有预见到在HashMap或类似的类中使用这个特定的类,因为它是类似RGBA类之间的中介,它使用int s作为内部存储,我'我有点担心在平等中使用浮动的一般情况。你只能使用于比较的epsilon如此之小,即使你可以任意减小,也有许多float值可以在内部以多种方式表示,从而导致从Float.floatToIntBits返回的不同值。解决这一切的最佳方法是什么?或者这不是现实中的问题而我只是在思考问题?

5 个答案:

答案 0 :(得分:4)

其他答案很好地解释了为什么您当前的设计可能会导致问题。我不是重复这一点,而是提出一个解决方案。

如果您只关心一定数量的小数位(它显示为4),您可以将所有传入的float值乘以10,000并将其作为long值进行管理。然后你的相等和哈希码计算是准确的。

我认为你为了简洁而省略了你班上的吸气剂。如果是这样,请确保您的Javadoc清楚地解释了将float传递给类构造函数并从getter中检索时会出现的精度损失。

答案 1 :(得分:1)

equals()的定义不具有传递性。它真的不应该被称为equals()。当在Collections API中使用时,这个和hashCode()问题很可能会无声地发生。像HashSet这样的东西不能按预期工作,像remove()这样的方法。出于此目的,您应该测试完全相等。

答案 2 :(得分:1)

我认为你关注hashCode()equals()大量分歧的一般情况是正确的。

违反一般惯例,即两个&#34;等于&#34;对象应该具有相同的hashCode(),如果将来使用此对象,很可能会导致各种意外行为。

对于初学者来说,任何通常假设不相等的hashCodes意味着不相等的对象的库代码会发现很多不相等的对象应该找到相同的对象,因为hashCode检查通常首先出现,以提高性能。

答案 3 :(得分:0)

hashcode就像定义一个对象应该驻留的存储桶。使用散列,如果一个对象不在其右侧存储桶中,则无法使用equals()方法找到该存储桶。

因此,所有equal个对象必须位于同一个存储桶中(即,它们的hashcode()方法应返回相同的结果),否则结果将无法预测。

答案 4 :(得分:0)

我认为您可以尝试削弱hashCode实施以防止其违反与equals的合同 - 我的意思是确保当equals返回true时,hashCode返回相同的价值,但不一定相反。