【问题标题】: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))
}

注意:(DoubleNumber的子类型)

运行上述代码产生:

1: false
2: true
3: true

我知道 comparingNaN 在 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(...)

    【讨论】:

    • @nrohwer,感谢您的评论,更新了答案。
    【解决方案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 Doubled1d2 的两个实例, 当且仅当d1.doubleValue() == d2.doubleValue() 的值也为真时,d1.equals(d2) 的值才为真。然而,有两个 例外:

    • 如果d1d2 都代表Double.NaN,则等于 方法返回 true,即使 Double.NaN==Double.NaN 具有值 false

    • 如果d1 代表+0.0d2 代表-0.0,反之亦然, 相等测试的值为 false,即使 +0.0==-0.0 具有 值true

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 2012-11-15
      • 2023-04-08
      • 2018-07-05
      • 2019-02-25
      相关资源
      最近更新 更多