为什么任何数据类型的范围在消极方面比积极方面更大?
例如,如果是整数:
在Turbo C中,它的范围是-32768
to 32767
,对于Visual Studio,它是-2147483648
to 2147483647
.
其他数据类型也会发生同样的情况......
[UPD:为Visual Studio设置适当的限制值]
为什么任何数据类型的范围在消极方面比积极方面更大?
例如,如果是整数:
在Turbo C中,它的范围是-32768
to 32767
,对于Visual Studio,它是-2147483648
to 2147483647
.
其他数据类型也会发生同样的情况......
[UPD:为Visual Studio设置适当的限制值]
因为数字的存储方式。带符号的数字使用称为“二进制补码表示法”的东西存储。
请记住,所有变量都有一定数量的位。如果其中最重要的一位,即左边的一位,是 0,则该数字为非负数(即正或零),其余位仅表示该值。
但是,如果最左边的位是 1,则该数字为负数。数字的真实值可以通过从表示的整数中减去 2^n 获得(作为无符号量,包括最左边的 1),其中 n 是变量具有的位数。
由于数字的实际值(“尾数”)只剩下 n - 1 位,因此可能的组合为 2^(n - 1)。对于正数/零数,这很容易:它们从 0 变为 2^(n - 1) - 1。 -1 是为了说明零本身——例如,如果你只有四种可能的组合,那些组合将代表 0、1、2 和 3(注意有四个数字):它从 0 变为 4 - 1。
对于负数,请记住最左边的位是 1,因此表示的整数介于 2^(n - 1) 和 (2^n) - 1 之间(括号在那里非常重要!)。但是,正如我所说,您必须带走 2^n 才能获得数字的实际值。2^(n - 1) - 2^n 是 -(2^(n - 1)),并且 ((2^n) - 1) - 2^n 是 -1。因此,负数的范围是 -(2^(n - 1)) 到 -1。
将所有这些放在一起,您会得到 -2^(n - 1) 到 2^(n - 1) - 1。如您所见,上限得到 -1,而下限没有。
这就是为什么负数比正数多一个的原因。
C 要求的最小范围实际上是 -32767 到 32767,因为它必须满足二进制补码、二进制补码和负数的符号/幅度编码,所有这些都是 C 标准允许的。有关数据类型的最小范围的详细信息,请参阅Annex E, Implementation limits
C11(和 C99)。
您的问题仅与二进制补码变体有关,原因很简单。使用 16 位,您可以表示 2 16(或 65,536)个不同的值,并且零必须是其中之一。因此剩下奇数个值,其中大多数(一个)是负值:
1 thru 32767 = 37267 values
0 = 1 value
-1 thru -32768 = 32768 values
-----
65536 values
一个的补码和符号幅度编码都允许负零值(以及正零),这意味着非零数可用的位模式减少了,因此您在标准中找到的最小范围减小.
1 thru 32767 = 37267 values
0 = 1 value
-0 = 1 value
-1 thru -32767 = 32767 values
-----
65536 values
二进制补码实际上是一种漂亮的编码方案,因为可以使用相同的简单硬件将正数和负数相加。其他编码方案往往需要更复杂的硬件来完成相同的任务。
有关二进制补码如何工作的更完整说明,请参阅维基百科页面。
因为范围包括零。一个 n 位整数可以表示的不同值的数量是 2^n。这意味着一个 16 位整数可以表示 65536 个不同的值。如果是无符号 16 位整数,则可以表示 0-65535(含)。有符号整数的约定是表示 -32768 到 32767、-214748368 到 214748367 等。
使用 2s 补码,负数被定义为按位不加 1,这将给定位数的可能数字的范围在负侧减少 1。
通常,由于使用二进制补码系统来存储负值,当您翻转整数上的符号位时,它会偏向负数。
范围应为:-(2^(n-1)) - ((2^(n-1)-1)