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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1726254/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 21:56:26  来源:igfitidea点击:

Why is Java's Double.compare(double, double) implemented the way it is?

javacomparisonfloating-point

提问by DavidS

I was looking at the implementation of compare(double, double)in the Java standard library (6). It reads:

我正在查看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)
}

What are the merits of this implementation?

这种实现的优点是什么?



edit: "Merits" was a (very) bad choice of words. I wanted to know how this works.

编辑:“优点”是一个(非常)糟糕的词选择。我想知道这是如何工作的。

采纳答案by Stephen C

@Shoover's answer is correct (read it!), but there is a bit more to it than this.

@Shoover 的答案是正确的(阅读它!),但还有更多内容。

As the javadocfor Double::equalsstates:

由于javadoc中Double::equals规定:

"This definition allows hash tables to operate properly."

“这个定义允许哈希表正常运行。”

Suppose that the Java designers had decided to implement equals(...)and compare(...)with the same semantics as ==on the wrapped doubleinstances. This would mean that equals()would always return falsefor a wrapped NaN. Now consider what would happen if you tried to use a wrapped NaN in a Map or Collection.

假设Java的设计者已经决定实施equals(...)compare(...)使用相同的语义==上的包裹double的情况。这意味着它equals()总是会返回false一个包裹的 NaN。现在考虑如果您尝试在 Map 或 Collection 中使用包装的 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.
}

Doesn't make a lot of sense does it!

没有多大意义吧!

Other anomalies would exist because -0.0and +0.0have different bit patterns but are equal according to ==.

其他异常现象会存在,因为-0.0+0.0有不同的位模式,但根据是相等的==

So the Java designers decided (rightly IMO) on the more complicated (but more intuitive) definition for these Double methods that we have today.

因此,Java 设计者决定(正确地 IMO)对我们今天拥有的这些 Double 方法进行更复杂(但更直观)的定义。

回答by phoebus

That implementation allows a real number to be defined as < NaN, and -0.0 as < 0.0.

该实现允许将实数定义为 < NaN,将 -0.0 定义为 < 0.0。

回答by shoover

The explanation is in the comments in the code. Java has double values for both 0.0and -0.0, as well as "not a number" (NaN). You can't use simple ==operator for these values. Take a peek into the doubleToLongBits()source and at the Javadoc for the Double.equals()method:

解释在代码的注释中。Java 对0.0and-0.0以及“非数字” ( NaN)都有双重值。您不能==对这些值使用简单运算符。查看方法doubleToLongBits()源代码和JavadocDouble.equals()

Note that in most cases, for two instances of class Double, d1and d2, the value of d1.equals(d2)is trueif and only if

d1.doubleValue() == d2.doubleValue()

also has the value true. However, there are two exceptions:

  • If d1and d2both represent Double.NaN, then the equals method returns true, even though Double.NaN == Double.NaNhas the value false.
  • If d1represents +0.0while d2represents -0.0, or vice versa, the equal test has the value false, even though +0.0 == -0.0has the value true.

This definition allows hash tables to operate properly.

请注意,在大多数情况下,类的两个实例Doubled1并且d2,该值d1.equals(d2)true当且仅当

d1.doubleValue() == d2.doubleValue()

也有价值true。但是,有两个例外:

  • 如果d1d2都表示Double.NaN,则 equals 方法返回true,即使Double.NaN == Double.NaN具有值false
  • 如果d1代表+0.0whiled2代表-0.0,反之亦然,则相等测试具有值false,即使+0.0 == -0.0具有值true

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

回答by Kevin Bourrillion

The merit is that it's the simplest code that fulfills the specification.

优点是它是满足规范的最简单的代码。

One common characteristic of rookie programmers is to overvalue reading source code and undervalue reading specifications. In this case, the spec:

菜鸟程序员的一个共同特征是高估阅读源代码而低估阅读规范。在这种情况下,规范:

http://java.sun.com/javase/6/docs/api/java/lang/Double.html#compareTo%28java.lang.Double%29

http://java.sun.com/javase/6/docs/api/java/lang/Double.html#compareTo%28java.lang.Double%29

... makes the behavior and the reason for the behavior(consistency with equals()) perfectly clear.

... 使行为和行为的原因(与 equals() 的一致性)非常清楚。