【问题标题】:correct way to compare double in equals()-method [duplicate]在equals()方法中比较double的正确方法[重复]
【发布时间】:2019-09-30 11:03:45
【问题描述】:

我的班级中有双重类型,必须重写 equals()/hashCode()。所以我需要比较双值。

哪种方法正确?

版本 1:

boolean isEqual(double a, double b){
    return Double.doubleToLongBits(a) == Double.doubleToLongBits(b);}

版本 2:

boolean isEqual(double a, double b){
    final double THRESHOLD = .0001;
    return Math.abs(a - b) < THRESHOLD;
}

或者我应该完全避免原始 double 并使用它的包装类型 Double 吗?有了这个我可以使用Objects.equals(a,b),如果ab 是Double。

【问题讨论】:

  • 你想要求双打完全相等还是几乎相等?请记住,“几乎相等”与将双精度值用作哈希码的一部分是不兼容的。
  • @khelwood 我想在类的重写 hashCode()/equals() 方法中使用此方法..
  • @nimo23 如果您有两个几乎相同但不完全相同的双打,您希望它们显示为相等还是不相等?
  • @nimo23 这没有回答 khelwood 的问题。你认为什么是“平等”?浮点值很容易出现微小的错误,即使它们应该是不相等的,也会使它们不相等。
  • 您的第一个版本检查值是否完全相同。第二个版本检查它们是否在彼此的.0001 内。哪一个(如果有的话)是合适的取决于你用它做什么。如果使用第二个,则必须在计算哈希码时省略双精度。

标签: java


【解决方案1】:

在 equals/hashcode 方法中使用的推荐方法[需要引用] 是分别使用 Double.doubleToLongBits()Double.hashcode()

这是因为如果哈希码不同,equals 的合约要求两个输入计算为“不同”。反之则无限制。

(注意:原来Double.compare()在内部使用doubleToLongBits(),但这不是API指定的。因此我不会推荐它。另一方面,hashCode() 确实 em> 指定它使用doubleToLongBits()。)

实际例子:

@Override
public boolean equals(Object obj) {
    if (obj == null || getClass() != obj.getClass())
        return false;

    Vector2d other = (Vector2d)obj;
    return Double.doubleToLongBits(x) == Double.doubleToLongBits(other.x) &&
           Double.doubleToLongBits(y) == Double.doubleToLongBits(other.y);
}

@Override
public int hashCode() {
    int hash = 0x811C9DC5;
    hash ^= Double.hashCode(x);
    hash *= 0x01000193;
    hash ^= Double.hashCode(y);
    hash *= 0x01000193;
    return hash;
}

【讨论】:

  • 你必须使用 return Double.compare(a, b) == 1;
  • 几乎正确,但很好。
  • @nimo23 Double.equals 使用 doubleToLongBits(-0.0 和 +0.0 不同)但具有 NaN 被视为相等的“优势”。总而言之,float 和 double 是不可救药的醉酒类型。
  • 我之前测试过,但不是。当您想平等对待它们时,您应该将双精度值“规范化”,或者作为类约束,或者在这些方法中使用它们。规范化就像x+0 一样简单,正如预期的那样将-0.0 转换为0.0。
  • 没有。对于doubleToLongBits,所有 NaN 都相等,对于 doubleToRawLongBits,只有相同的 NaN 相等。注意:除 Double.NaN 之外的任何 NaN 都不会作为表达式的结果生成,只有在您使用 Double.longBitsToDouble() 时才会生成。
【解决方案2】:

double不应用作建立对象相等性及其哈希码的组件。

这是因为浮点数存在固有的不精确性,并且在+/-Infinity处人为地双重饱和

为了说明这个问题:

System.out.println(Double.compare(0.1d + 0.2d, 0.3d));
System.out.println(Double.compare(Math.pow(3e27d, 127d), 17e256d / 7e-128d));

打印:

1
0

...转化为以下 2 个虚假陈述

0.1 + 0.2 > 0.3

(3 * 1027)127 == 17 * 10256 / (7 * 10-128 )

因此,您的软件将使您对 2 个不相等的相等数字,或者 2 个非常大或非常小的不相等数字相等。

【讨论】:

  • 谢谢,好点子。我会考虑的。。
猜你喜欢
  • 2015-02-22
  • 1970-01-01
  • 2012-03-08
  • 2012-01-15
  • 1970-01-01
  • 2018-12-31
  • 2011-01-12
  • 2020-07-04
  • 2015-11-15
相关资源
最近更新 更多