将int转换为short会产生意外结果

时间:2012-08-07 14:07:38

标签: c# casting

我对C#中数字类型的丢失信息感到有些困惑。

当我这样做时:

int x = 32780;
short y = (short)x;

我有结果:-32756为y而不是预期的32767.为什么?如何计算?

短期范围:-32768至32767 范围:-2,147,483,648至2,147,483,647

5 个答案:

答案 0 :(得分:53)

你似乎期待一种“四舍五入”的效果,而不是实际发生的事情,这是对数据的逐位重新解释。

在二进制中,x等于00000000000000001000000000001100,这是一个32位数,只有16位有效位。 short是一个16位签名的整数,使用two’s complement notation表示。

转换后,x的最后16位将被复制到y,并提供1000000000001100。重要的是,第一个数字是1。在二进制补码表示法中,这是-32756。你的号码没有被舍入 - 它被读作好像是16位。

答案 1 :(得分:14)

请阅读丹的答案,了解发生这种情况的“真实”原因,但这样就足够了:当一个数字溢出其最大值时,它会回绕到最小值。所以,32780 - 32767 = 13-32768 (which is one of the 13) + 12 (the other 12) = -32756

答案 2 :(得分:6)

可以说运行时添加或减去65536所需的次数,以获得shortSystem.Int16)类型范围内的数字。

如果你知道很多纯数学,而不是通过内部二进制表示(也很酷)来解释它,你可以从modular arithmetic理解它。

为此,请将类型short视为模数为65536的整数,也写为ℤ/65536ℤ。 ℤ/65536ℤ的每个成员都是同余类,即除以65536时所有具有相同余数的数字。现在,每个同余类具有不同成员(“代表”)的无限。如果您选择一个,则通过重复添加或减去65536来获得所有其他。

使用short数据类型,我们会在-32768+32767的时间间隔内选择唯一代表。然后ushort是同一件事,我们只会在065535中选择代表。

现在关于ℤ/65536ℤ的一个很酷的事情就是它形成了ring,其中我们有加法减法乘法(但除法)。实际上,在unchecked上下文中,使用short x,y;,C#操作

(short)(x + y)
(short)(x - y)
(short)(x * y)

完全对应于ℤ/65536ℤ中的算术。 (我们必须在此转换回short,因为从技术上讲,C#仅为intuintlongulong定义运算符。)

以同样的方式,sbytebyte可以被认为是戒指ℤ/256ℤ,intuint为ℤ/4294967296ℤ,{{1 }和long为ℤ/18446744073709551615ℤ。

然而,请注意,因为这些模数不是素数,所以在环中不可能除法。例如,没有ulong满足

int X

因此不清楚unchecked( 10 * X == 35 ) // integers Int32 应该是什么。另一方面,两个 35/10满足

X

但是哪一个应该是unchecked( 10 * X == 36 ) // integers Int32

然而,只有一个36/10使

int X

真。我们有运气,因为11对于4294967296是相对素数。解unchecked( 11 * X == 35 ) // integers Int32 是1952257865(自己检查),所以商X在某种意义上是35/11

结论:C#的整数运算X+-可以简单地解释为ℤ/nℤ中的环运算。但是*操作与戒指没有任何关系!

答案 3 :(得分:3)

当您将x转换为short时,您将获得溢出(即分配的值超出其可处理的值),并且您的值将表示为从min值开始再次重新开始。正如你所说,short的最大值是32767所以你的新值将是:-32768 +(32780 - 32768)= -32756

根据编程语言(可能还有编译器),您尝试做的事情可能会带来异常。它似乎在C#中没有。

答案 4 :(得分:2)

有溢出。如果您希望将数字限制为最大值,可以通过将整数与short.MaxValue进行比较来解决此问题:

short y;
if (x > short.MaxValue) {
    y = short.MaxValue;
} else if (x < short.MinValue) {
    y = short.MinValue;
} else {
    y = (short)x;
}
相关问题