为什么Java&的Double.Compare(Double,Double)是这样实现的?

2022-06-24 00:00:00 floating-point comparison java

我正在研究Java标准库(6)中compare(double, double)的实现。上面写着:

public static int compare(double d1, double d2) {
    if (d1 < d2)
        return -1;       // Neither val is NaN, thisVal is smaller
    if (d1 > d2)
        return 1;        // Neither val is NaN, thisVal is larger

    long thisBits = Double.doubleToLongBits(d1);
    long anotherBits = Double.doubleToLongBits(d2);

    return (thisBits == anotherBits ?  0 : // Values are equal
            (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
             1));                          // (0.0, -0.0) or (NaN, !NaN)
}

此实现的优点是什么?


编辑:"优点"是一个(非常)糟糕的措辞。我想知道这是如何工作的。


解决方案

@Shoover的答案是正确的(read it!),但还有更多的原因。

作为Double::equals的javadoc状态:

此定义允许哈希表正常运行。

假设Java设计者已经决定使用与包装的double实例上的==相同的语义来实现equals(...)compare(...)。这意味着对于包装的NaN,equals()总是返回false。现在考虑如果您尝试在地图或集合中使用包装的NaN会发生什么情况。

List<Double> l = new ArrayList<Double>();
l.add(Double.NaN);
if (l.contains(Double.NaN)) {
    // this wont be executed.
}

Map<Object,String> m = new HashMap<Object,String>();
m.put(Double.NaN, "Hi mum");
if (m.get(Double.NaN) != null) {
    // this wont be executed.
}

没什么意义,不是吗!

将存在其他异常,因为-0.0+0.0具有不同的位模式,但根据==相同。

因此,Java设计人员决定(正确地使用IMO)为我们今天拥有的这些双重方法选择更复杂(但更直观)的定义。

相关文章