我正在研究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)
}
这种实施的优点是什么?
编辑:“优点”是一个(非常)糟糕的选择。我想知道它是如何工作的。
答案 0 :(得分:43)
解释在代码中的注释中。 Java对0.0
和-0.0
以及“非数字”(NaN
)都有双重值。您不能对这些值使用简单的==
运算符。查看doubleToLongBits()
来源和the Javadoc for the Double.equals()
method:
请注意,在大多数情况下,两个 类
Double
,d1
和d2
的实例, 如果,d1.equals(d2)
的值为true
并且只有在d1.doubleValue() == d2.doubleValue()
也具有值
true
。然而, 有两个例外:
- 如果
d1
和d2
都代表Double.NaN
,那么equals方法会返回true
,甚至 虽然Double.NaN == Double.NaN
的值为false
。- 如果
d1
代表+0.0
而d2
代表-0.0
,反之亦然,则等值测试的值为false
,即使+0.0 == -0.0
}具有值true
。此定义允许哈希表正常运行。
答案 1 :(得分:40)
@ Shoover的答案是正确的(请阅读!),但还有更多的内容。
Double::equals
状态为javadoc:
“此定义允许哈希表正常运行。”
假设Java设计者决定在包装的equals(...)
实例上使用与compare(...)
相同的语义实现==
和double
。这意味着equals()
总是会为包裹的NaN返回false
。现在考虑如果您尝试在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.
}
没有多大意义吗!
存在其他异常,因为-0.0
和+0.0
具有不同的位模式但根据==
相等。
因此,Java设计人员(正确的IMO)决定了我们今天使用的这些Double方法的更复杂(但更直观)的定义。
答案 2 :(得分:2)
优点是它是满足规范的最简单的代码。
新手程序员的一个共同特征是高估阅读源代码并低估阅读规范。在这种情况下,规范:
http://java.sun.com/javase/6/docs/api/java/lang/Double.html#compareTo%28java.lang.Double%29
...使行为和行为的原因(与equals()的一致性)完全清楚。
答案 3 :(得分:0)
该实现允许将实数定义为&lt; NaN和-0.0&lt; 0.0。