比较Kotlin中的NaN

Apl*_*nus 12 floating-point nan 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))
}
Run Code Online (Sandbox Code Playgroud)

NB :( Double 是子类型 )Number

运行上面的代码会产生:

1: false
2: true
3: true
Run Code Online (Sandbox Code Playgroud)

我理解与Java 相比,我会期望所有的表达式.NaNfalsefalse

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

hot*_*key 10

这是因为(2)(3)被编译为装箱基元,然后Double.equals检查:在JVM上,基元double不能与盒装基元进行比较.

Double.equals反过来,通过比较doubleToLongBits(...)两个Doubles来检查相等性,而后者则保证这一点

如果参数是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));
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为,如果你提到从[文件]以下行你的答案是更完整的(https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#doubleToLongBits(双) )`doubleToLongBits`:**除了所有NaN值折叠成单个"规范"NaN值**.否则你可能会认为两个不同的`NaN`将与该函数的false相比较. (2认同)

mie*_*sol 8

第一个比较等同于Java:

double left = Double.NaN;
double right = Double.NaN;
boolean result = left == right;
Run Code Online (Sandbox Code Playgroud)

正如您在这个答案中读到的,这是标准化和记录在案的行为.

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

Double left = Double.valueOf(Double.NaN);
Number right = Double.valueOf(Double.NaN);
boolean result = left.equals(right);
Run Code Online (Sandbox Code Playgroud)

哪个使用Double.equals:

请注意,在大多数情况下,对于两个实例class Double,d1d2,d1.equals(d2)当且仅当d1.doubleValue() == d2.doubleValue()值也为true时,值为true.但是,有两个例外:

  • 如果d1d2两者都表示Double.NaN,那么true即使Double.NaN==Double.NaN有值 ,equals方法也会返回false.

  • 如果d1代表+0.0while d2表示-0.0,反之亦然,则等值测试具有该值false,即使+0.0==-0.0具有该值true.