【问题标题】:Comparing NaN in Kotlin比较 Kotlin 中的 NaN
【发布时间】:2016-10-19 10:38:06
【问题描述】:
所以我最近开始喜欢 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))
}
注意:(Double是Number的子类型)
运行上述代码产生:
1: false
2: true
3: true
我知道 comparing 和 NaN 在 Java 中返回 false,所以我希望所有表达式都使用 false。
如何解释这种行为?
其背后的原理是什么?
【问题讨论】:
标签:
floating-point
nan
kotlin
【解决方案1】:
那是因为 (2) 和 (3) 被编译成装箱原语,然后 Double.equals 检查:在 JVM 上,原语 double 不能与盒装的相比。
Double.equals 反过来通过比较两个Doubles 中的doubleToLongBits(...) 来检查相等性,对于后者,可以保证
如果参数为 NaN,则结果为 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(...)。
【解决方案2】:
第一个比较等价于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:
请注意,在大多数情况下,对于 class Double、d1 和 d2 的两个实例,
当且仅当d1.doubleValue() ==
d2.doubleValue() 的值也为真时,d1.equals(d2) 的值才为真。然而,有两个
例外: