【问题标题】:Meaning of Double.doubleToLongBits(x)Double.doubleToLongBits(x) 的含义
【发布时间】:2014-06-19 18:01:51
【问题描述】:

我正在写一个类Vec2D,代表一个二维向量。我将xy 存储在doubles 中。

当被要求生成 equals(Object objhashCode() 时,eclipse 生成了这个:

@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吗?

【问题讨论】:

    标签: java eclipse equals hashcode


    【解决方案1】:

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

    当且仅当参数不是null 并且是一个表示double 的Double 对象时,结果为true,该对象与该对象表示的double 具有相同的值。为此,当且仅当方法doubleToLongBits(double) 在应用于每个long 值时返回相同的long 值时,两个double 值被认为是相同的。

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

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

    另一个问候NaN:

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

    确实,当且仅当 x 的值为 NaN 时,测试 x!=xtrue

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

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

    【讨论】:

    • +0.0==-0.0 结果为真,你能解释一下如何吗?我阅读了 java 文档,他们提到了同样的情况。但我无法理解相等运算符如何导致true。我的意思是它是如何在内部计算的?
    • @PrasannaSasne 这是一个与这个问题截然不同的问题。如果您想了解更多详细信息,最好使用链接到此问题和答案的顶级问题来询问。不过,作为预览,Java 字节码指定 floating-point compare operations,而像 x86 这样的汇编语言 have floating point opcodes,所以我的半知半解的猜测是“Java 虚拟机将其委托给物理处理器”。
    【解决方案2】:

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

    不过,老实说,我想说doubleToLongBits 的使用在这里是一个错误,因为如果您关心完全相等,您应该使用Double.doubleToRawLongBits()(它不会对double 的数据执行任何翻译全部)代替。

    【讨论】:

    • 其实在doubleToLongBits里面,它调用了doubleToRawLongBits
    【解决方案3】:

    快速浏览一下在线 javadoc 会得出这样的结论:

    根据 IEEE 754 浮点“双格式”位布局返回指定浮点值的表示形式。

    ...

    在所有情况下,结果都是一个长整数,当将它提供给 longBitsToDouble(long) 方法时,将产生一个与 doubleToLongBits 的参数相同的浮点值(除了所有 NaN 值都折叠为单个“规范的“NaN 值)。

    所以这可能是标准化xydouble表示的一种方式,因为NaN可以有多个double表示

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-03
      • 2015-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多