为什么在 C# 中的 sbyte returns 0 中转换 big double 值?

Why casting big double value in sbyte returns 0 in C#?

我实际上在未经检查的上下文中测试了 C# 中的转换行为。正如文档所说,在未经检查的上下文中,转换总是成功的。但有时,在特定情况下,从一种特定类型转换为另一种类型会产生意想不到的结果。

例如,我测试了三个 "double to sbyte" 演员表:

var firstCast = (sbyte) -129.83297462979882752;          // Result : 127.
var secondCast = (sbyte) -65324678217.74282742874973267; // Result : 0.
var thirdCast = (sbyte) -65324678216.74282742874973267;  // Result : 0.

需要说明的是,第二个和第三个 double 之间的区别只是 1 (secondDouble - firstDouble = 1)。 在这种情况下,对于任何 "big" 双精度值,转换结果似乎总是 0

我的问题是:为什么第二次和第三次转换会导致 0? 我在 C# 文档中搜索了答案,但没有找到。

我用 .Net Framework 4.7.2 测试了上面的内容。

根据 C# language specification,

For a conversion from float or double to an integral type, the processing depends on the overflow checking context in which the conversion takes place:

不使用 checkedunchecked 运算符,默认情况下不检查溢出检查上下文,所以我们看:

In an unchecked context, the conversion always succeeds, and proceeds as follows.

  • If the value of the operand is NaN or infinite, the result of the conversion is an unspecified value of the destination type.

  • Otherwise, the source operand is rounded towards zero to the nearest integral value. If this integral value is within the range of the destination type then this value is the result of the conversion.

  • Otherwise, the result of the conversion is an unspecified value of the destination type.

这里的值既不是 NaN 也不是无穷大。当向零舍入时,它们不在 sbyte 的有效范围内,即 -128 到 127,因此适用最后一个要点,这意味着此类转换的结果未指定。

换句话说,此转换的结果取决于您使用的编译器。不同的编译器可以做不同的事情,它们仍然被称为 C# 编译器。当要转换的值非常远离 lower/upper 界限时,很可能您使用的任何编译器都认为将 return 0 用于转换是一个更好的主意。