【问题标题】:Inconsistency in java.lang.Double implementation (Oracle JDK 1.8)?java.lang.Double 实现不一致(Oracle JDK 1.8)?
【发布时间】:2019-08-09 16:08:01
【问题描述】:

我查看了java.lang.Double 类的实现。 NaN 的值是0x7ff8000000000000L 的指定值。 public static final double NaN 字段设置为 0.0d / 0.0,如果 JVM 确实以这种方式实现它,则它应该评估为 0x7ff8000000000000L

  1. 为什么选择这个值 (0x7ff8000000000000L)?该值有什么特别之处(例如它的位掩码)吗?

  2. 为什么该字段被隐式设置为该值并取决于0.0d / 0.0 操作的底层实现,而静态方法public static long doubleToLongBits(double value) 将值显式设置为0x7ff8000000000000L 用于NaN 参数?隐式设置它不是更安全吗,因为0.0d / 0.0 的结果高度依赖于 JVM 的实现并且理论上可以更改(很可能永远不会)?

POSITIVE_INFINITYNEGATIVE_INFINITY 也是如此。字段被隐式设置为其值,但某些方法使用显式指定值。这背后有什么原因吗?

感谢您帮助我每天学习新事物 :-)。

【问题讨论】:

  • 1.这是 IEEE754 中指定的值。
  • as the result of 0.0d / 0.0 highly depends on the implementation of the JVM and could be changed - 不,JLS 指定 0.d/0.0 返回 NaN,因此 0.d/0.0 根据定义为 NaN。
  • @AndyTurner:这是 IEEE754 中指定的其中一个值。但另一个也可以。特别是,NaN 不与其他浮点数进行比较,因为即使相同的值也不等于它自己:Double.NaN == Double.NaNfalse。但是他们都会为Double.isNaN返回true
  • 0x7ff8000000000000L 是一个 long 的事实确实排除了它在指定双值字段时的用途。

标签: java java-8 double jls


【解决方案1】:

public static final double NaN 字段设置为 0.0d / 0.0,如果 JVM 确实以这种方式实现,则它的计算结果应为 0x7ff8000000000000L

不:它导致NaN,根据the language spec

零除以零的结果是 NaN

0x7ff8000000000000Llong,而不是 double,因此不能直接用作字段初始值设定项。

The documentation of Double.NaN 确实声明其值“等同于Double.longBitsToDouble(0x7ff8000000000000L) 返回的值”。但是,0.0d / 0.0 优先用于初始化字段,因为它是编译时常量值,而方法调用不是。

my answer about why it is 0.0d, not 0.0 的无耻插件)


为什么选择这个值 (0x7ff8000000000000L)?

JLS Sec 4.2.3中所述:

IEEE 754 允许其单双浮点格式中的每一种都有多个不同的 NaN 值。虽然每个硬件架构在生成新的 NaN 时都会返回特定的 NaN 位模式,但程序员也可以创建具有不同位模式的 NaN 来编码,例如追溯诊断信息。

在大多数情况下,Java SE 平台将给定类型的 NaN 值视为折叠为单个规范值,因此本规范通常将任意 NaN 称为规范值。

Double.longBitsToDouble 方法必须返回 a 值,所以这是他们选择返回的值。

【讨论】:

  • AFAICS 选择的 NaN 是 long 中的最小值。
猜你喜欢
  • 1970-01-01
  • 2015-08-25
  • 2015-10-22
  • 2016-09-24
  • 2014-07-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
相关资源
最近更新 更多