为什么将Double.NaN转换为int不会在Java中抛出异常?

Mic*_*wan 18 java floating-point casting ieee-754

所以我知道IEEE 754为非实数的值指定了一些特殊的浮点值.在Java中,铸造这些值的原始int不会抛出异常像我本来期望.相反,我们有以下内容:

int n;
n = (int)Double.NaN; // n == 0
n = (int)Double.POSITIVE_INFINITY; // n == Integer.MAX_VALUE
n = (int)Double.NEGATIVE_INFINITY; // n == Integer.MIN_VALUE
Run Code Online (Sandbox Code Playgroud)

在这些情况下抛出异常的理由是什么?这是IEEE标准,还是仅仅是Java设计者的选择?如果这种演员阵容有例外情况,我是否会发现不良后果?

Ste*_*n C 11

在这些情况下不抛出异常的理由是什么?

我想这个原因包括:

  • 这些是边缘情况,很可能在执行此类事情的应用程序中很少发生.

  • 这种行为并非"完全出乎意料".

  • 当应用程序从double转换为int时,预计会出现重大的信息丢失.该应用程序要么忽略这种可能性,要么演员之前将进行检查以防止它...这也可以检查这些情况.

  • 没有其他双重/浮动操作会导致异常,而(IMO)在这种情况下执行它会有点精神分裂.

  • 某些硬件平台(当前或未来)可能会出现性能损失.

这是IEEE标准,还是仅仅是Java设计者的选择?

我认为后者.

如果这种演员阵容有例外情况,我是否会发现不良后果?

没有明显的......

(但它并不是真正相关.JLS和JVM规范说出了他们的意思,改变它们将会破坏现有的代码.而且我们现在谈论的不只是Java代码......)


我做了一些挖掘.许多可以使用的x86指令从double转换为整数似乎生成硬件中断......除非屏蔽.(对我而言)不清楚指定的Java行为是否比OP建议的替代方案更容易或更难实现.

  • 我怀疑没有转换抛出异常的决定是出于强烈的愿望,即出于任何原因避免抛出异常,因为害怕强制代码将其添加到`throws`子句中.但是,从实际角度来看,如果代码试图将浮点数转换为整数并且它不适合,则代码不太可能正常工作,因此异常可能比继续伪造数据更好. (2认同)

Edw*_*rzo 8

在这些情况下不抛出异常的理由是什么?这是IEEE标准,还是仅仅是Java设计者的选择?

第20页和第21页的IEEE 754-1985标准在2.2.1 NANs和2.2.2 Infinity部分下清楚地解释了标准要求NAN和Infinity值的原因.因此这不是Java的事情.

Java虚拟机规范3.8.1浮点运算及IEEE 754规定,如果转换到整体的类型进行了那么JVM将应用到零,说明您所看到的结果四舍五入.

该标准确实提到了一个名为"陷阱处理程序"的功能,该功能可用于确定何时发生溢出或NAN,但Java虚拟机规范明确指出这不是针对Java实现的.它在第3.8.1节中说:

Java虚拟机的浮点操作不会抛出异常,陷阱或以其他方式发出IEEE 754无效操作异常条件,除零,溢出,下溢或不精确的信号.Java虚拟机没有信令NaN值.

因此,无论后果如何,都不会指明行为.

如果这种演员阵容有例外情况,我是否会发现不良后果?

理解标准中陈述的理由应该足以回答这个问题.该标准用详尽的例子解释了你在这里要求的后果.我会发布它们,但这里的信息太多了,在这个版本工具中无法正确格式化示例.

编辑

我正在阅读最近由JCP发布的Java虚拟机规范的最新维护评论,作为他们在JSR 924上的工作的一部分,在2.11.14部分中,命名类型转换结构包含一些可以帮助您寻求的更多信息.答案,还不是你想要的,但我相信它会有所帮助.它说:

在将浮点值缩小到数值转换为整数类型T(其中T为int或long)时,浮点值将按如下方式转换:

  • 如果浮点值为NaN,则转换结果为
    int或long 0.
  • 否则,如果浮点值不是无穷大,则 使用IEEE 754 向零模式
    舍入将浮点值四舍五入为
    整数值V.

有两种情况:

  • 如果T很长并且该整数值可以表示为long,则
    结果是长值V.
  • 如果T的类型为int,并且此整数值可以表示为int,则结果为int值V.

除此以外:

  • 值必须太小(大幅度或负无穷大的负值),结果是int或long类型的最小可表示值.
  • 或者值必须太大(大幅度或正
    无穷大的正值),结果
    是int或long类型的最大可表示值.

从double到float的缩小数字转换符合IEEE 754.使用IEEE 754 round到最近模式正确舍入结果.太小而不能表示为float的值将转换为float类型的正零或负零; 太大而无法表示为float的值将转换为正无穷大或负无穷大.双NaN总是转换为浮子NaN.

尽管可能发生溢出,下溢或精度损失,但缩小数字类型之间的转换不会导致Java虚拟机抛出运行时异常(不要与IEEE 754浮点异常混淆).

我知道这只是重述你已经知道的东西,但它有一个线索,似乎IEEE标准要求四舍五入到最近.也许在那里你可以找到这种行为的原因.

编辑

第2.3.2节"舍入模式状态"中讨论的IEEE标准:

默认情况下,舍入表示向最近的方向舍入.该标准要求提供其他三种舍入模式; 即向0舍入,向+无限圆并向无穷大舍入.

当与转换为整数运算一起使用时,舍入为-Infinity会导致转换成为floor函数,而舍入+ Infinity则为ceiling.

模式舍入会影响溢出,因为当朝向O舍入或朝向-Infinite舍入为有效时,正幅度溢出会导致默认结果为最大可表示数字,而不是+无穷大.

类似地,负向量的溢出将在向+无穷大或向O向着圆的情况下产生最大的负数.

然后他们继续提到一个为什么这在区间运算中有用的例子.不确定,这是您正在寻找的答案,但它可以丰富您的搜索.

  • 看起来你正在指向IEEE标准来证明NaN和无穷大的存在.我绝不会争辩说这些值应该是IEEE标准或Java的一部分,所以我不确定你为什么指向它.此外,"向零舍入"并不能自动解释决定; 这种舍入在数学上没有明确定义.鉴于决定转向*某些东西*那些是明智的选择,但不明显的是必须作出决定. (2认同)