题
我写Java代码的交互R,其中"NA"价值观的区别,从南的价值观。NA表示一个数值为"统计上的缺失",这是它可能没有收集,或者是否则不提供。
class DoubleVector {
public static final double NA = Double.longBitsToDouble(0x7ff0000000001954L);
public static boolean isNA(double input) {
return Double.doubleToRawLongBits(input) == Double.doubleToRawLongBits(NA);
}
/// ...
}
以下单元的测试表明的关系之间南和NA和运行的现在我的窗户的笔记本电脑,但"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改变为规范的南值7ff8000000000000L,但这很难说,因为印它stdout提供了不同的数值比调试器。
还有,测试只有失败,如果它运行之后,其他一些以前的试验;如果我运行这个试验单独的,它始终通过。
这是一个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
值。
该文件 longBitsToDouble()
有这个注:
注意,这种方法可能无法返回
double
南用完全相同的位模式,为长期参数。IEEE754之间的区别两种类型的Nan,安静南斯和信南斯.之间的区别两种类型的南一般不可见。算术运算上的信南斯变成他们安静的南斯有不同,但往往相似,位模式。然而,在一些处理器是仅仅复制信南也执行这一转换。特别是,复制信南返回它的叫法可能执行这种转换。所以longBitsToDouble
可能不能够恢复双与信南位模式。因此,一些长期价值,doubleToRawLongBits(longBitsToDouble(start))
可能不等于start
.此外,这特别是位模式表示信Nan是平台的依赖;虽然所有南位模式,安静或信,必须在南的范围。
所以假设,处理 double
值将始终保持 具体 NaN
值完整是一个危险的事情。
的 最干净的 解决办法是存储数据 long
和转换 double
后 检查你的特殊价值。这将处以相当明显的性能产生影响,但是。
你的 可能会 摆脱通过加入 strictfp
标志在受影响的地方。这并不以任何方式 保证 它将工作,但它会(可能是)更改如何JVM处理的浮点的价值观和 可能会 只是有必要的暗示,可以帮助。它将 仍然 不是便携式的,但是。