补码这点事,希望这次能说清楚。

补码这点事,希望这次能说清楚。

部分抄自:https://www.zhihu.com/question/405701348/answer/1329114111
首先,8位二进制一共可以提供256个“码点”;那么我们就总可以用这些“码点”来编码256种符号。8位二进制码的自然顺序是:0000_0000 ~ 0111_1111~ 1000_0000~1111_1111。然后溢出,得到0000_0000…。
直接看这个自然顺序对应的原码反码补码表示的数据。

补码这点事,希望这次能说清楚。_第1张图片

原码与反码

原码是一种很初级的编码方案,它仅仅解决了编码问题——从此数字有办法二进制表示了。
但我们在计算机内部表示数字是用来计算的;那么想用原码计算的话,那可就麻烦了……
我们知道,最初CPU的内部最重要的核心器件叫ALU(Arithmetic and Logic Unit算术逻辑单元),其中的A就是数学。
ALU的核心是加法器,这是个随参与计算的数值的二进制位数指数增长的数字电路。较早期的CPU里面绝大多数的逻辑门都被拿来做这个加法器了。
加法器顾名思义只能拿来做加法。
但是没关系,如果你调过机械表,就知道从8点调到1点的方式有两种:一种是往后拨7个小时,一种是往前拨5个小时。
换句话说,在时钟钟面上,8-7 和 8+(12-7) 效果相同,最终得到的都是1.
类似的,1个字节的加减法,如果计算结果超过 255 就会造成溢出,溢出的高位二进制数据无处存放自动丢弃,计算结果就出错了——但反过来想,这不恰恰就是一个逻辑钟面吗?
显然,我们也可以利用这个性质做减法:减32完全可以当成加 (256-32) 来算嘛;而由于二进制的特点,256-32 恰好又等于32这个数值取反。
类似的,有符号数其实是一个符号位和7个二进制位,7个二进制位能表示的最大数是 127;因此减 32 就可以用加 (128-32) 代替(和表盘上的12点/0点一样)。
于是,减法器就可以不做,一个加法器就足够用了——省了好大一坨门电路,CPU的制造成本一下子就去了一大块。
既然最终减法一定要这样做……那么从一开始就不应该用原码表示负数,对吧。
不然每次计算都还得用一条指令判断判断符号位,然后该取反取反……这速度可就慢下去了。
如果从一开始,负数就取反表示,那么负数加法完全无需判断,拎起来就加——圆满。
这个编码方案就是所谓的反码。
反码是一个充满了工程师的恶臭味的优秀方案。
说它优秀,是因为它的确解决问题;说它恶臭,是因为它用起来实在麻烦,需要很多“微妙”的调整才能得到正确结果。
反码行为奇特的根本原因在于,它有两个零:+0 和-0,分别对应于 00000000和10000000 ——还记得吗?我们规定第一位是符号位。因此最前面的0/1是±号,并不是数值。
但+0 和-0 都是 0. 它们是同一个数据,却得到了两个码点。
所以要调整。注意这个调整是计算过程的一部分,每次计算都必须即时调整。

补码

一个更好的方案叫补码。
256个不同的二进制编码,我们需要给它们分别指定一个意义。
我们希望它们是连续的编码,且基于二进制的排序不能打乱。

原码的问题在于,它的编码排列“不按固定顺序”,使得因此必须把负数先“颠倒”一下(实际上取反)才能用;而反码头疼医头脚疼医脚,大致保证了编码顺序,却没能消除额外的无效码点,造成在±0这个位置两个码点对应一个编码。
这两个编码都得人工调整。
而补码,没有跳跃,没有重复。(见上图)perfect。这里我们是倒推的,人设计补码的初衷其实就是设计一 其自然变化过程可以没有跳跃、没有重复地表示数据。

你可能感兴趣的:(数学,数电)