为什么将NaN转换为长期产生有效结果?

在下面的示例代码中,我除以零,当我使用调试器逐步执行时,(dividend / divisor)产生无穷大或NaN(如果除数为零)。 当我将此结果转换为长时间时,我得到一个有效的结果,通常类似于-9223372036854775808。 为什么这个演员有效? 为什么不停止执行(例如抛出exception)而不是分配任意值?

double divisor = 0; double dividend = 7; long result = (long)(dividend / divisor); 

为什么这个演员有效?

如果在编译时已知转换可能成功或始终成功,则转换有效。 只有在转换无法成功时,转换才是非法的。 (例如,将密封类型转换为未实现的接口。)从double到long的转换可能会成功。 因此演员表是有效的。

为什么不停止执行(例如抛出exception)而不是分配任意值?

因为你没有要求例外! 该规范非常清楚预期的行为是什么。 见6.2.1节:

对于从float或double到整数类型的转换,处理取决于发生转换的溢出检查上下文:

在已检查的上下文中,转换过程如下:

•如果操作数的值为NaN或无穷大,则抛出System.OverflowException。

[…]

在未经检查的上下文中,转换始终成功,并按如下方式继续。

•如果操作数的值为NaN或无穷大,则转换结果为目标类型的未指定值。

您正在未经检查的上下文中执行代码; 你没有要求任何例外,所以你没有例外。 如果你想要一个例外,请求一个; 使用检查的上下文。

默认情况下,未选中C#算术,因此无效操作不会引发exception。

您可以使用checked块来强制运行时检查溢出和抛出exception,如下所示:

 checked { double divisor = 0; double dividend = 7; long result = (long)(dividend / divisor); } 

请注意,会有轻微的性能损失。

该行为在C#语言规范第6.2.1节中明确记录:

对于从float或double到整数类型的转换,处理取决于转换发生的溢出检查上下文(第7.5.12节):

在已检查的上下文中,转换过程如下:

  • 如果操作数的值为NaN或无穷大,则抛出System.OverflowException。
  • 否则,源操作数向零舍入为最接近的整数值。 如果此整数值在目标类型的范围内,则此值是转换的结果。
  • 否则,抛出System.OverflowException。

在未经检查的上下文中,转换始终成功,并按如下方式继续。

  • 如果操作数的值为NaN或无限,则转换的结果是目标类型的未指定值。
  • 否则,源操作数向零舍入为最接近的整数值。 如果此整数值在目标类型的范围内,则此值是转换的结果。
  • 否则,转换的结果是目标类型的未指定值。

大胆增加强调。 你有无限和未经检查的背景。 你得到的价值是未指定的。 使用checked关键字使其成为炸弹。

编译时也可以使用“checked”标志,这与在check-block中包装所有代码的方式相同。

这取决于数据类型。 除以零之外,不同的数据类型将具有不同的结果。

http://blogs.msdn.com/rafats/archive/2006/07/20/673337.aspx

http://www.eggheadcafe.com/software/aspnet/30920566/divide-by-zero-question.aspx

来自Jon Skeet在其他网站(以上链接):

总之,标准。 至少,我怀疑这就是原因。 float / double遵循IEC 60559标准的算术规则,包括除以零,导致“无限”值而不是抛出exception。

十进制没有(或者至少没有 – C#规范允许这种可能性)支持“无限”值,而float / double则支持。 类似的小数没有指定NaN。

除以零解释: http : //www.philforhumanity.com/How_to_Divide_by_Zero.html