补码的原理: 为什么 127 + 1 = -128
?#
为什么不在答疑范畴?#
不知道为什么, C++ 课开始时很喜欢谈码制这些东西, 实际上对于 C++ 初期的学习是完全没用的.
在 C++ 中, 有符号数的溢出 (例如此处的 127 + 1 = -128) 是未定义行为, 任何事情都可能发生: 你的软件可能因为这个未定义行为崩溃, 你的电脑可能因为这个未定义行为爆炸.
跟码制同样没用的是记忆基础的 int
, long
等类型的精度和存储大小, 这会根据所在平台不同而变化, 因而完全没有意义, 只是在初学者增加负担.
为什么 127 + 1 = -128
?#
码制存在的原因是, 计算机的存储是有限的而数字是无限的. 例如此处的 127 + 1 = -128
是由 8 位二进制构成的补码, 即 0000'0000
, 总共有 \(2^8\) 种取值可能. 有限的取值可能意味着只能表示一定范围内的数字, 而补码的选择是表示一定范围内的负数、零及正数.
更重要的是, 补码是为了便于计算机计算而产生的, 它在不溢出的情况下, 完美地支持 +1 和 -1 运算; 当溢出时, 超出表示范围的进位/借位可以忽略不计, 即:
1 1111'1111
2+ 0000'0001
3-----------
41|0000'0000 (忽略超出范围的进位 1, 得到 0000'0000)
我们可以借此来推断它如何分配值:
首先规定,
0000'0000
表示零.-1 得到
1111'1111
, 这就是-1
.为什么是
1111'1111
呢? 这里理解起来比较方便的方法是反过来想: 什么东西 +1 能得到0000'0000
? 上面的例子中已经给出了, 是1111'1111
.+1 得到
0000'0001
, 这就是1
.
这样我们便规定, 0000'0000
表示零, 0xxx'xxxx
表示正数, 1xxx'xxx
表示负数.
那么,
最大的正数 (一直 +1) 就是
0111'1111
, 即十进制 127.最小的负数 (一直 -1) 就是
1000'0000
, 即十进制 -128.这里依然可以反过来理解, 什么东西以
1xxx'xxxx
的格式, 但是需要最多次 +1 才能得到最大的负数1111'1111
.
可以看到, 最大的正数再 +1, 就会得到最小的负数. 因而 8 位二进制补码下, 127 (0111'1111) + 1 = -128 (1000'0000)
.