在上一篇笔记《从逻辑门到 CPU》中提到了补码的一些知识,以及补码的深入意义,但是我自己感觉还不是特别清楚,因为我试着让我的室友平哥阅读,他说没看懂,于是我决定专门针对补码写一篇笔记,再来仔细说一下原码、反码和补码

原码 sign-magnitude

sign 有符号之意,magnitude 有大小之意,引申为数值,所以 sign-magnitude 就是 “符号-数值”组合,也就是我们常说的,用最高位表示符号位,其余位表示数值位
原码对于正数来说是很友好的,正数的相加用原码来计算,是没有任何问题的(这里不讨论溢出的情况),比如 2(0010)+4(0100)=6(0110)
但是一旦计算减法,我们再使用原码,就算不对了:4 - 2 (10进制)= 4 + (-2)= 0 100 + 1 010 (二进制原码) = 1110 (二进制原码)= -6 (10进制),即 4-2 算出-6,所以原码在计算减法的时候,是不可用的,因为CPU 在进行运算的时候,是不知道最高位表示符号位的,他只会把每一位都当做数值位来进行计算

补数和同余:

严格地定义的话,补数应该是和模共生共存的,没有模就没有补数,没有补数模也就没什么意义,还是以上一篇文章讲的时钟为例,现在 9 点钟,我想要得到 8 点钟,有两种方法:

  1. 时针向前拨动 1 小时,如果“向前”这个动作用-号表示,可以记为-1。
  2. 时针向后拨动 11 小时,如果“向后”这个动作用+号表示,可以记为+11。

从这个例子中,我们可以抽象出模和补数的概念,定义模为这个运算中最大能表示的数,或者说到了这个模再往上加就会溢出,或者说是一个周期、一个最大范围都可以,叫什么名字无所谓,关键是你理解了模是什么,显然,这个例子中 12 就是那个模(记做(mod 12)),以此类推,我们在 4bit 能表示的数中,16 就是那个模
有了模的概念,再看这个例子中,我们称:-1 就是 +11 以 12 为模的补数,当然,反过来也对:+11 就是 -1 以 12 为模的补数,分别记做:
-1 ≡ +11(mod 12)
+11 ≡ -1(mod 12)
当然,还可以写很多:
-3 ≡ +9(mod 12)
+4 ≡ -8(mod 12)
等等……
上面的记法还有一种读法,也可以读作:-1 和 11 关于模 12 同余(-1 和 11 对 12 取余结果都是 11,对于负数求余有一个简单易记的方法:就是对负数加模,加到正为止,得到的最小正数就是负数关于模的余数,当然这个方法也是脱胎于严谨的求余数学公式的),因为在数论中有定理:同余的两个数具有互补关系

以计算 5-3 为例,因为
5 ≡ 5(mod 12) 同余的反身性
-3 ≡ +9(mod 12)
所以,根据 同余满足线性运算的定理,有:
5-3 ≡ 5+9(mod 12)

因此,5-3 的答案就可以由 (5 mod 12)+ (-3 mod 12) 得到,这样就把减法转变为了加法,把所有数统一用补码表示,都能算对

在计算机中,不管是 4bit,8bit,16bit,我们都可以轻易知道,模就是 2^n
所以只要确定了膜,我们就可以找到一个和负数等价的正数(和负数同余的正数),来代替这个负数,从而把减法变为加法,要得到这个正数,我们可以用模减去这个负数的绝对值得到(这个正数其实就是这个负数的补码,就是 2^n- |N| (N为负),也就是刚刚说的同余数互补,注意一点就是负数的补码比如-3 的补码 1101,其实就是+13,最高位不是什么符号位啦!)
因为没办法直接计算减法,所以有了取反的操作,其实取反就是一种特殊的减法,因为他可以达到减法的效果:
比如一个 4bit 的负数 N,要想得到反码 ,理论上需要计算 负数N 的反码为 1111-|N|(1111-0011=1100),但是现在没办法用减法,所以直接让 N 的绝对值按位取反,从而实现了N 的反码,在反码的基础上,我们又发现补码有更简单的计算方式,就是反码+1,所以就用反码加 1 计算补码了,但不要忘记,负数 N 的补码的真正意义是2^n- |N| ,反码+1 只是他的计算方式而已(这句是本文核心)

反码 ones' complement & 补码 tow's complement

这里要注意,反码是ones' complement 不是 one's complement 也就说,one 是负数,反码直译过来就是很多 1 的补数
反码的英文ones' complement的意思就是以“一串 1”为模,一个数的补数 ,所以上文讲的反码就是用一串 1 来当做模
补码的英文tow's complement的意思就是以“2”为模,一个数的补数 但这里是老外起名字没那么准确,tow's complement要表达的真实含义是以“2的 n 次幂”为模,一个数的补数

闲话

秋招基本结束,本来我以为自己是 996 的坚定反对者,无数次想象自己帅气地对 HR 说我不接受你们公司这么严重的加班,可是当HR 在我面前 pia pia 按计算器,然后指着上面的 30 对我说,这是您的最终薪资,一年最终可以到手 30W时,我真的犹豫了,幸好有半天考虑时间,思考再三,还是帅气地拒绝了,选了一家 不到 20W 的 965 的公司,用 10W 来买我对编程的热请和身心健康,希望我的决定没有错