C++中整数取值范围是-32768到32767,而不是到32768
因为C++中的有符号整数通常采用“二进制补码”表示法,而这种方法使得负数的范围比正数的范围大1。
下面我们来详细解释一下。
1. 核心原因:二进制补码
现代计算机几乎 universally 使用 二进制补码 来表示有符号整数。这种表示法有以下几个关键点:
-
最高位是符号位:在16位整数中,最高位(第15位)为0表示正数,为1表示负数。
-
非负数的表示:和非负整数(包括0)的表示方式完全一样。
-
0表示为0000 0000 0000 0000 -
1表示为0000 0000 0000 0001 -
...
-
32767表示为0111 1111 1111 1111(这是最高位为0时能表示的最大值)
-
-
负数的表示:一个负数的补码是通过其对应正数的二进制表示“取反(所有位0变1,1变0)再加1”得到的。
-
例如,求
-1的表示:-
1的二进制:0000 0000 0000 0001 -
取反:
1111 1111 1111 1110 -
加1:
1111 1111 1111 1111-> 这就是-1
-
-
求
-32768的表示:-
32768的二进制是1000 0000 0000 0000(注意,这已经是一个17位的数了,对于16位系统,32768本身是无法直接表示的)。 -
这里有一个特殊情况。在16位补码中,模式
1000 0000 0000 0000被直接定义为-32768。
-
-
2. 数值范围的计算
一个16位的二进制数,总共有 2^16 = 65536 种不同的组合。
在补码规则下,这些组合被分配如下:
-
正数:从
0到32767。-
数量:
32768个 (包括0)
-
-
负数:从
-1到-32768。-
数量:
32768个
-
所以,总范围是 -32768 到 32767。
3. 为什么不能表示 +32768?
关键在于 0 占用了一个编码。如果我们试图表示 +32768,它的二进制应该是什么?
-
最大的正数
32767的二进制是0111 1111 1111 1111。 -
要得到
+32768,理论上需要将最高位变为1,即1000 0000 0000 0000。
但是,在16位补码体系中,这个二进制模式 1000 0000 0000 0000 已经被规定为 -32768 了!
你可以验证一下补码的规则:
-
如果
1000 ... 0000是+32768,那么它的补码(取反加一)应该是-32768。 -
对
1000 ... 0000取反得到0111 ... 1111。 -
加1后得到
1000 ... 0000,也就是它自己。这会产生歧义。
为了避免这种歧义和简化硬件设计,补码标准直接定义这个模式为 -32768。因此,没有一个16位的二进制组合可以用来唯一地表示 +32768。
总结表格
| 数值范围 | 二进制表示(16位) | 数量 |
|---|---|---|
| 0 | 0000 0000 0000 0000 |
1个 |
| 正数 (1 到 32767) | 0000 0000 0000 0001 到 0111 1111 1111 1111 |
32767个 |
| 负数 (-1 到 -32767) | 1111 1111 1111 1111 到 1000 0000 0000 0001 |
32767个 |
| 负数 (-32768) | 1000 0000 0000 0000 |
1个 |
| 总计 | 65536个 |
重要提示:关于“16位”的假设
你问题中的“-32768 到 32767”是16位有符号整数的典型范围。但需要注意的是:
-
C++标准并没有规定
int类型必须是16位。它只规定了int的最小范围必须至少包含 -32767 到 32767(即至少16位)。 -
在现代大多数系统(如Windows, Linux, macOS on x86-64架构)上,
int通常是32位的,其范围是 -2,147,483,648 到 2,147,483,647。 -
你可以通过
sizeof(int) * CHAR_BIT来检查你当前平台上int的位数。
结论:取值范围的不对称性(-32768 到 32767 而不是到 32768)是二进制补码表示法的直接结果,这种设计使得算术运算(尤其是加法)在硬件层面变得非常简单和统一。
更多推荐
所有评论(0)