java - 最终的、非规范的 NaN double 值在运行时发生变化

标签 java jvm-crash

我正在编写与 R 交互的 Java 代码,其中“NA”值与 NaN 值不同。 NA 表示一个值“统计缺失”,即无法收集或不可用。

class DoubleVector {
     public static final double NA = Double.longBitsToDouble(0x7ff0000000001954L);

     public static boolean isNA(double input) {
         return Double.doubleToRawLongBits(input) == Double.doubleToRawLongBits(NA);
     }

     /// ... 
}

以下单元测试演示了 NaN 和 NA 之间的关系,并且在我的 Windows 笔记本电脑上运行良好,但“isNA(NA) #2”在我的 ubuntu 工作站上有时失败。

@Test
public void test() {

    assertFalse("isNA(NaN) #1", DoubleVector.isNA(DoubleVector.NaN));
    assertTrue("isNaN(NaN)", Double.isNaN(DoubleVector.NaN));
    assertTrue("isNaN(NA)", Double.isNaN(DoubleVector.NA));
    assertTrue("isNA(NA) #2", DoubleVector.isNA(DoubleVector.NA));
    assertFalse("isNA(NaN)", DoubleVector.isNA(DoubleVector.NaN));
}

从调试来看,DoubleVector.NA 似乎已更改为规范的 NaN 值 7ff8000000000000L,但很难判断,因为将其打印到标准输出给出的值与调试器提供的值不同。

此外,只有在之前的许多其他测试之后运行测试才会失败;如果我单独运行此测试,它总是会通过。

这是 JVM 错误吗?优化的副作用?

测试总是通过:

java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) Client VM (build 19.1-b02, mixed mode, sharing)

测试有时会失败:

java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)

最佳答案

您正踏入非常危险的水域,这是 Java VM 行为完全指定的少数区域之一。

根据 JVM 规范,double 范围内只有“一个 NaN 值”。对 double 的算术运算无法区分两个不同的 NaN 值。

The documentation of longBitsToDouble()有这个注释:

Note that this method may not be able to return a double NaN with exactly same bit pattern as the long argument. IEEE 754 distinguishes between two kinds of NaNs, quiet NaNs and signaling NaNs. The differences between the two kinds of NaN are generally not visible in Java. Arithmetic operations on signaling NaNs turn them into quiet NaNs with a different, but often similar, bit pattern. However, on some processors merely copying a signaling NaN also performs that conversion. In particular, copying a signaling NaN to return it to the calling method may perform this conversion. So longBitsToDouble may not be able to return a double with a signaling NaN bit pattern. Consequently, for some long values, doubleToRawLongBits(longBitsToDouble(start)) may not equal start. Moreover, which particular bit patterns represent signaling NaNs is platform dependent; although all NaN bit patterns, quiet or signaling, must be in the NaN range identified above.

因此假设处理 double 值将始终保持特定 NaN 值不变是一件危险的事情。

最干净 的解决方案是将您的数据存储在long 中,并在检查您的特殊值(value)。但是,这将对性能产生非常显着的影响。

可能通过在受影响的地方添加strictfp 标志来逃脱。这不会以任何方式保证它会工作,但它会(可能)改变您的 JVM 处理浮点值的方式并且可能只是必要的提示,有助于.但是,它仍然不可移植。

关于java - 最终的、非规范的 NaN double 值在运行时发生变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6371965/

相关文章:

java - 正则表达式打印出里面的所有匹配项?和 , 或 )

java - 根据 HashMap 中的比较值从数组中删除值

java - 了解 hs_err_pid<n>.log 文件

java - Eclipse 3.5 和 ubuntu 9.10 中的问题

java - JMeter 的 JVM 在 10 分钟后崩溃

Java jar在ubuntu上创建多个进程但在mac上不创建

java - 我可以使用 Writer 类生成 xlsx 文件吗?

java - 将 GUI 功能添加到编写 XML 文件的 Java 程序中

java - JVM 崩溃..如何获取错误日志或核心转储

java - 如何修复 Eclipse Java 虚拟机启动器错误?