当将NaN转换为整数时,为什么取决于它是否被分配给一个变量,其值会发生改变?

4
将double.NaN转换为int将得到0。
Console.WriteLine(unchecked((int)double.NaN));    // 0

然而,将 double.NaN 分配给一个变量,然后进行 int 强制转换将得到 -2147483648。

double value = double.NaN;
Console.WriteLine (unchecked ((int) value));    // -2147483648
Console.WriteLine ((int) value);                // -2147483648

为什么将结果分配给变量与不分配给变量时结果会有所不同?
C#规范6.2.1中显示数字转换:
在checked上下文中,转换过程如下:
- 如果操作数的值为NaN或无穷大,则抛出System.OverflowException。 - 否则,源操作数向零舍入到最接近的整数值。如果该整数值在目标类型的范围内,则该值是转换的结果。 - 否则,抛出System.OverflowException。
在unchecked上下文中,转换总是成功,并按以下方式进行。
- 如果操作数的值为NaN或无穷大,则转换的结果是目标类型的未指定值。 - 否则,源操作数向零舍入到最接近的整数值。如果该整数值在目标类型的范围内,则该值是转换的结果。 - 否则,转换的结果是目标类型的未指定值。
环境:
- 编译器:Visual Studio 2013 - 运行时:.NET Framework 4.6.0 - 操作系统:Windows 10 Version 1607 - CPU:Intel Core i7 920
Windows:
Console.WriteLine(Environment.OSVersion);    // Microsoft Windows NT 6.2.9200.0
Console.WriteLine(Environment.Version);      // 4.0.30319.42000

2
我建议你看一下IL - 我怀疑编译器正在执行第一次转换,并将结果硬编码为0。而在变量情况下,你是在要求CLR去做这件事。 - Jon Skeet
4
我无法复现。当我尝试时,Console.WriteLine(unchecked((int)double.NaN));输出-2147483648 - Matthew Watson
1
你使用的编译器版本是什么?我也没有得到0 - DaveShaw
1
这让我想起了无数关于 C 语言的“为什么 int *c; printf("%d", *c); 会打印出 37 的未定义行为问题”。规范告诉你它将是某个未指定的数字。如果每次运行程序时都是不同的数字,你甚至不应该感到惊讶。 - itsme86
1
你处于“鼻妖”(Nasal Demons)的领域中,它返回了两个不同的数字,因为它“感觉如此”。 - Scott Chamberlain
显示剩余7条评论
2个回答

3
默认情况下,控制台应用程序编译为unchecked。这就是为什么您的最后一个示例显示与显式使用unchecked的示例相同的值。
对于您的其他示例,适用您引用的规范部分:
在未经检查的上下文中,转换始终成功,并按以下方式进行。 - 如果操作数的值为NaN或无穷大,则转换的结果是目标类型的未指定值。(由我强调) 未指定表示您不能依赖结果。它可以是0-2147483648或其他任何值。
我想弄清楚在您特殊情况下发生了什么,但两种方法都会得到-2147483648。所以很难跟踪。

我也无法在我的系统上重现它,但是将.NET Fiddle编译器更改为“.NET 4.5”而不是“Roslyn 1.0.0-rc1”,它会显示为零:https://dotnetfiddle.net/ckfngN - Quantic

1

看了一下,我觉得我明白这里发生了什么。你没有将0强制转换,而是将NaN强制转换。 intInt32的范围比double要小得多。我认为这些不太清晰的规则共同作用导致了差异:

  • 如果操作数的值为NaN或无限大,则转换的结果是目标类型的未指定值。 否则,源操作数将向零舍入到最接近的整数值。
  • 如果此整数值在目标类型的范围内,则此值是转换的结果。
目标类型是较小的int,而您得到的值“-2147483648”是32位有符号整数的最小值。这表明强制转换操作将NaN转换为double.NegativeInfinity以执行操作。最接近double.NegativeInfinity的整数是int.MinValue,这就是您得到的值。
所有这些都说了,这个值是未指定的事实意味着您得到的结果可能取决于太多因素,甚至可以归结为您是否分配了变量或者您拥有什么处理器架构。您不应该使用NaN转换来做任何有意义的事情,因此NaN从来没有被赋予实际的设置值(主要是因为那样它就会成为一个数字)。出于这个原因,对于大多数目的,NaN结果应该被视为错误。最终,实际值是无意义的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接