Double.double的含义ToLongBits(x)

2022-09-04 02:11:33

我正在写一个类,表示一个二维向量。我存储和在s。Vec2Dxydouble

当被要求生成 和 时,eclipse 生成如下:equals(Object objhashCode()

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    long temp;
    temp = Double.doubleToLongBits(x);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(y);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Vec2D other = (Vec2D) obj;
    if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
        return false;
    if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
        return false;
    return true;
}

在这方面,其意义何在?我不能简单地写吗?Double.doubleToLongBits(x)x != other.x


答案 1

简短的回答:Eclipse使用Double.doubleToLongBits,因为这就是Double.equals所做的:

结果是当且仅当参数不是 并且是一个 Double 对象,它表示与此对象所表示的值相同的 e。为此,当且仅当方法 doubleToLongBits(double) 在应用于每个值时返回相同的值时,才认为两个值是相同的。truenulldoubldoubledoublelong

长答案:JLS 指定了 Double.equals 和 == 之间的一些差异。对于 JLS 4.2.3JLS 15.21.1 中指定的一个差异:

正零和负零比较相等;因此,表达式的结果是 和 的结果为 。但其他操作可以区分正零和负零;例如,具有正无穷大的值,而 的值为负无穷大。0.0==-0.0true0.0>-0.0false1.0/0.01.0/-0.0

另一个方面:NaN

如果任一操作数为 NaN,则 的结果为 是,但结果为 。==false!=true

实际上,检验是当且仅当 x 的值是 NaN。x!=xtrue

如您所见,两个双精度值可以与 == 进行比较,但在数学和哈希表中使用时,实际上对应于不同的行为。因此,在编写生成的相等方法时,Eclipse 会假设两个双精度值仅当且仅当可以对它们执行的所有操作都相同时才相等,或者(等效地)如果它们被自动装箱并与它们的方法进行比较。如果在 和 之间切换,这一点尤其重要 — 相等属性在那里有所不同尤其出乎意料。equalsdoubleDouble

当然,您可以自由地偏离该假设:无论这是否是一个好主意,您都可以将特殊情况分配给许多可能的NaN表示中的任何一个,在这种情况下,这将是您和方法的更好匹配。出于同样的原因,您的用例可能会将具有 +0.0 和 -0.0 的对象视为等效对象,并保证 NaN 值是不可能的,在这种情况下,原始比较可能更有效(但在这一点上,模拟相同的标准变得困难)。Double.doubleToRawLongBits()equalshashCode==equalshashCode


答案 2

因为 和 遵循 IEEE-754 语义的双精度和 .这些行为可能不是您想要的,因此会将 64 位数据转换为 64 位数据,以便位移位和 XOR 等操作正常工作。==!=Double.NaN != Double.NaN0.0 == -0.0Double.doubleToLongBits()doublelong

不过,老实说,我想说的是,这里的使用是一个错误,因为如果你关心确切的相等性,你应该使用Double.doubleToRawLongBits()(它根本不对数据执行任何转换)。doubleToLongBitsdouble


推荐