为什么在sbyte中使用大的双精度值在C#中返回0?

为什么在sbyte中使用大的双精度值在C#中返回0?,c#,casting,double,.net-4.7.2,sbyte,C#,Casting,Double,.net 4.7.2,Sbyte,实际上,我在未经检查的上下文中测试了C#中的强制转换行为。正如文档所说,在未经检查的环境中,演员阵容总是成功的。但有时,在特定情况下,从一种特定类型转换到另一种类型会产生意外的结果 例如,我测试了三个“double to sbyte”类型转换: 需要明确的是,第二个双精度和第三个双精度之间的差异只是1(secondDouble-firstDouble=1)。 在这种情况下,对于任何“大”双倍值,铸造结果似乎总是0 我的问题是:为什么第二次和第三次强制转换会导致0? 我在C#文档中寻找答案,但没有

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

例如,我测试了三个“double to sbyte”类型转换:

需要明确的是,第二个双精度和第三个双精度之间的差异只是
1
secondDouble-firstDouble=1
)。 在这种情况下,对于任何“大”双倍值,铸造结果似乎总是
0

我的问题是:为什么第二次和第三次强制转换会导致
0
? 我在C#文档中寻找答案,但没有找到任何答案

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

根据

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

如果不使用
checked
unchecked
运算符,则默认情况下溢出检查上下文为unchecked,因此我们看一下:

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

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

  • 否则,源操作数将向零舍入到最接近的整数值。如果此整数值在目标类型的范围内,则此值是转换的结果

  • 否则,转换的结果是目标类型的未指定值

这里的值既不是NaN也不是无限的。当四舍五入到零时,它们不在有效范围内,即-128到127,因此最后一个项目符号适用,这意味着此类转换的结果未指定

换句话说,此强制转换的结果取决于您使用的编译器。不同的编译器可以做不同的事情,它们仍然被称为C#编译器。很可能您正在使用的任何编译器都认为,当要转换的值远离下限/上限时,最好返回0进行转换

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

如果不使用
checked
unchecked
运算符,则默认情况下溢出检查上下文为unchecked,因此我们看一下:

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

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

  • 否则,源操作数将向零舍入到最接近的整数值。如果此整数值在目标类型的范围内,则此值是转换的结果

  • 否则,转换的结果是目标类型的未指定值

这里的值既不是NaN也不是无限的。当四舍五入到零时,它们不在有效范围内,即-128到127,因此最后一个项目符号适用,这意味着此类转换的结果未指定


换句话说,此强制转换的结果取决于您使用的编译器。不同的编译器可以做不同的事情,它们仍然被称为C#编译器。无论您使用的是哪种编译器,当要转换的值远离下限/上限时,最好返回0进行转换。

sbyte的范围仅为-128到127。我不希望这两种类型转换都有任何实际意义或产生有意义的结果,并且没有得到异常的唯一原因是未检查的上下文。此外,这两个文本的精度已经超过了双精度文本的精度。不确定c#是否会这样,但这可能是因为它充当循环列表吗?正如Joel所提到的,最小值是-128。因此,当铸造-129时,它将达到-128+1=>127(最大值)-128链接到127,我得到-73,不是0。浮点数存储为尾数和指数。单字节为4字节,双字节为8字节。因此,当您强制转换为一个字节时,编译器只接受第一个字节或4/8字节对象。我猜它首先强制转换为int,然后接受低sbyte。在第二个示例中,强制转换为int将导致0x8000000,结果是0。如果您首先强制转换为long,然后再转换为sbyte-您得到0xB6-“(sbyte)(long)-65324678216.74282774973267”-强制转换为long的结果是0xFFFFFFF0CA5883B6sbyte的范围仅为-128到127。我不希望这两种类型转换都有任何实际意义或产生有意义的结果,并且没有得到异常的唯一原因是未检查的上下文。此外,这两个文本的精度已经超过了双精度文本的精度。不确定c#是否会这样,但这可能是因为它充当循环列表吗?正如Joel所提到的,最小值是-128。因此,当铸造-129时,它将达到-128+1=>127(最大值)-128链接到127,我得到-73,不是0。浮点数存储为尾数和指数。单字节为4字节,双字节为8字节。因此,当您强制转换为一个字节时,编译器只接受第一个字节或4/8字节对象。我猜它首先强制转换为int,然后接受低sbyte。在第二个示例中,强制转换为int将导致0x8000000,结果是0。如果您首先对long进行强制转换,然后对sbyte进行强制转换-您得到0xB6-“(sbyte)(long)-65324678216.7428742874973267”-对long进行强制转换的结果是0xfffffff0ca5883b6有趣,所以我没有
var firstCast = (sbyte) -129.83297462979882752;          // Result : 127.
var secondCast = (sbyte) -65324678217.74282742874973267; // Result : 0.
var thirdCast = (sbyte) -65324678216.74282742874973267;  // Result : 0.