C# 为什么将一个NaN转换为一个long会产生一个有效的结果?

C# 为什么将一个NaN转换为一个long会产生一个有效的结果?,c#,C#,在下面的示例代码中,我将除以零,当我使用调试器逐步通过它时,(被除数/除数)会产生无穷大或NaN(如果除数为零)。当我将这个结果转换为long时,我得到了一个有效的结果,通常类似于-9223372036854775808。为什么这个演员阵容有效?为什么它不停止执行(例如抛出一个异常)而不是分配一个任意值 double divisor = 0; double dividend = 7; long result = (long)(dividend / divisor); 这取决于数据类型。对于被零

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

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

这取决于数据类型。对于被零除,不同的数据类型将有不同的结果

来自不同站点的Jon Skeet(以上链接):

一句话,标准。至少,我怀疑这就是原因。 float/double遵循IEC 60559算术标准规则, 包括被零除的结果是“无限”值,而不是 正在引发异常

Decimal没有(或者至少没有) 必须-C#规范允许这种可能性)支持“无限” 值,而浮点/双精度。相似的 decimal没有指定NaN

除零解释:

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

您可以使用强制运行时检查溢出并引发异常,如下所示:

checked {
    double divisor = 0;
    double dividend = 7;

    long result = (long)(dividend / divisor);
}
请注意,会有轻微的性能损失。

您也可以在编译时使用“checked”标志,其工作方式与将所有代码包装到checked块中的方式相同

为什么这个演员阵容有效

如果在编译时知道转换可能成功或总是成功,则转换是有效的。只有当转换不可能成功时,强制转换才是非法的。(例如,将密封类型强制转换为它未实现的接口。)从double到long的转换可能会成功。因此,强制转换是有效的

为什么它不停止执行(例如抛出一个异常)而不是分配一个任意值

double divisor = 0;
double dividend = 7;
long result = (long)(dividend / divisor);
因为你没有要求例外!规范非常清楚预期的行为是什么。见第6.2.1节:

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

在选中的上下文中,转换按如下方式进行:

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

[……]

在未检查的上下文中,转换始终成功,并按如下方式进行

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


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

该行为在C语言规范第6.2.1节:

对于从float或double到integral类型的转换 处理取决于溢出检查上下文(§7.5.12),其中 转换发生在:

在选中的上下文中,转换按如下方式进行:

  • 如果操作数的值为NaN或无穷大,则 抛出System.OverflowException
  • 否则,源操作数将向零舍入到整数 最近的整数值。如果该整数值在 目标类型然后此值是转换的结果
  • 否则,将抛出System.OverflowException
在未检查的上下文中,转换始终成功并继续 具体如下

  • 如果操作数的值为NaN或无穷大,则 转换是目标类型的未指定值。
  • 否则,源操作数将向零舍入到整数 最近的整数值。如果该整数值在 目标类型然后此值是转换的结果
  • 否则,转换的结果是未指定的值 目标类型

为强调起见,增加了粗体。你有无限和未检查的上下文。您获得的值未指定。使用选中的关键字使其爆炸。

您是否尝试查看由该代码生成的
MSIL
。。。Eric Lippert请到前台来。在C#中,这样一个演员的效果是否和在C中一样,即决定如何解释原始存储?顺便说一下,
1.0/0.0
Double.Infinity
,而不是
Double.NaN
“蝙蝠信号人”:如果有什么你想引起我注意的话,考虑在我的博客上使用“联系”链接。我理解除法结果,但我不理解的是如何将无效除法结果(ie NaN)转化为一个有效的结果(在这种情况下是长的)。因为在技术上除以零在数学上是合法的。它不是用数字来表示的。他们在浮点运算中实现了被零除,某种程度上反映了这一点。