在 Kotlin 中比较 NaN

Comparing NaN in Kotlin

所以我最近开始喜欢上了 kotlin 语言。今天,在比较双打时,我遇到了不可避免的NaN

fun main(args: Array<String>) {
    val nan = Double.NaN
    println("1: " + (nan == nan))
    println("2: " + (nan == (nan as Number)))
    println("3: " + ((nan as Number) == nan))
}

N.B:(Double 的子类型 Number)

运行 上面的代码产生:

1: false
2: true
3: true

我明白 comparingNaN 在 Java returns false 中,所以我希望所有表达式都是 false

如何解释这种行为? 背后的原理是什么?

那是因为 (2)(3) 被编译为装箱原语,然后 Double.equals 检查:开JVM,原始 double 无法与盒装相比。

两个 Double 中的

Double.equals, in turn, checks equality by comparing doubleToLongBits(...),而对于后者,可以保证

If the argument is NaN, the result is 0x7ff8000000000000L.

所以,两个NaN返回的位是相等的,这里忽略规则NaN != NaN

此外,正如 @miensol 提到的,这种相等性检查还有另一个结果:+0-0 根据 == 是相等的检查而不是 equals 检查。

Java 中的等效代码为:

double nan = Double.NaN;
System.out.println("1: " + (nan == nan)) //false 
System.out.println("2: " + ((Double) nan).equals(((Number) nan)))
System.out.println("3: " + ((Number) nan).equals(nan));

最后两行调用Double.equals,比较doubleToLongBits(...).

第一次比较相当于Java的:

double left = Double.NaN;
double right = Double.NaN;
boolean result = left == right;

尽你所能 read in this answer 这是标准化和记录在案的行为。

第二次和第三次比较相当于:

Double left = Double.valueOf(Double.NaN);
Number right = Double.valueOf(Double.NaN);
boolean result = left.equals(right);

其中使用 Double.equals:

Note that in most cases, for two instances of class Double, d1 and d2, the value of d1.equals(d2) is true if and only if d1.doubleValue() == d2.doubleValue() also has the value true. However, there are two exceptions:

  • If d1 and d2 both represent Double.NaN, then the equals method returns true, even though Double.NaN==Double.NaN has the value false.

  • If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0==-0.0 has the value true.