19

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

当我这样做时:

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

我得到了结果:y 为 -32756 而不是预期的 32767。为什么?这是如何计算的?

short 范围:-32768 到 32767 int 范围:-2,147,483,648 到 2,147,483,647

4

5 回答 5

53

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

在二进制中,x等于00000000000000001000000000001100,它是一个只有 16 个有效位的 32 位数字。Ashort是一个 16 位有符号整数,使用二进制补码表示法表示

当您转换时,您的最后 16 位将x被复制y1000000000001100. 重要的是,第一个数字是1. 在二进制补码表示法中,这是-32756. 你的数字没有被四舍五入——它被认为是 16 位的。

于 2012-08-07T14:12:48.393 回答
14

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

于 2012-08-07T14:12:43.820 回答
6

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

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

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

使用short数据类型,我们选择区间中的唯一代表-32768+32767. 那么ushort也是一样的,只是我们在0through中挑选代表65535

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

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

完全对应ℤ/65536ℤ中的算术。(我们必须回到short这里,因为从技术上讲,C# 只为intuintlong和定义了运算符ulong。)

同理,sbyteandbyte可以被认为是环ℤ/256ℤ,ℤ/4294967296ℤ,andint是ℤ/18446744073709551615ℤ。uintlongulong

但是请注意,因为这些模不是素数,所以在环中不能进行除法。例如,int X不满足

unchecked( 10 * X == 35 )   // integers Int32

因此不清楚35/10应该是什么。另一方面,两个 X满足

unchecked( 10 * X == 36 )   // integers Int32

但他们中的哪一个应该是36/10

然而,正是一个int X使

unchecked( 11 * X == 35 )   // integers Int32

真的。我们很幸运,因为 11 与 4294967296 相对质数。解X是 1952257865(自己检查),所以商35/11在某种意义上就是这个数字X

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

于 2012-08-07T16:45:08.000 回答
3

当您将 x 转换为 short 时,您将得到一个溢出(即分配的值超出了它可以处理的范围)并且您的值将被表示为认为它会从最小值开始重新开始。正如你所说,short 的最大值是 32767,所以你的新值是:-32768 + (32780 - 32768) = -32756

根据编程语言(可能还有您的编译器),您尝试执行的操作可能会带来异常或不带来异常。在 C# 中似乎没有。

于 2012-08-07T14:17:31.767 回答
2

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

short y;
if (x > short.MaxValue) {
    y = short.MaxValue;
} else if (x < short.MinValue) {
    y = short.MinValue;
} else {
    y = (short)x;
}
于 2012-08-07T14:15:53.057 回答