原码 反码 补码的原理

CPU中以二进制来表示和计算数据,为了进行算数运算,先后出现了以下三种编码:原码,反码和补码。

名称 英文 用途
原码 Sign-Magnitude 最直观的人类写法
反码 Ones’ Complement 过渡形式,历史上用过
补码 Two’s Complement 现代计算机通用

原码

最高位表示符号:0=正,1=负
剩下的位表示数值大小
优点:直观
缺点:有“+0”和“-0”两个表示方式,需要专门的减法电路
这里的+0和-0没有数学上的意义,单纯是表示上的差别
00000000 表示 +010000000表示-0 有时候做两数相等比较的时候会比较麻烦
如果要实现 A-B,则必须:

  1. 检查符号位
  2. 做加法或减法
  3. 根据符号位调整结果

例如对于8位二进制数:

十进制 原码二进制
+5 00000101
-5 10000101

例1: -1 + -1 (原码)
步骤:

  • +1(原码)0000 0001
  • -1(原码)1000 0001

两数相加(原码):

1
2
3
4
1000 0001
+1000 0001
-----------
1 0000 0010 (溢出位1)

结果变成 0000 0010(把符号位当普通位加了) → 实际是 +2,不正确。
💡 在原码下,-1 + -1 得不到 -2,必须用单独的减法指令或额外处理逻辑才行。

例2:2+(-3) (原码)
步骤

  • +2(原码)0000 0010
  • -3(原码)1000 0011

相加:

1
2
3
4
0000 0010
+1000 0011
-----------
1000 0101

这被解释为 -5(原码),但正确答案应是 −1-1−1。
💡 在原码下做正数 + 负数很难直接得到正确结果,需要硬件做“减法”并判断符号。

反码

正数:和原码一样
负数:在原码基础上符号位不变,数值位按位取反
缺点:仍然有“+0”和“-0”两种表示和“末位进位回加”问题(end-around carry)。

如果要实现A-B时可以这样做:
A+(B的反码)
反码加法中:

  • 当两个符号位相加后,产生了一个“多出来的”进位到最高位以外。
  • 具体来说:当两个数同号,或一个数是负数另一个是正数,但反码相加时结果大于最大可表示的正值,会产生环绕进位。

📌 重点记忆
只要反码相加结果溢出了最高位,且你要得到正确值,就要把溢出的1加回最低位。

例1:8 位反码:

  • +2 (反码) = 0000 0010
  • +3 (反码) = 0000 0011

相加:

1
2
3
4
0000 0010
+0000 0011
-----------
0000 0101 (没有溢出,不用回加)

例2:典型的回加例子(-1 + -1)

  • -1 原码 = 1000 0001 → 反码 = 1111 1110

再加 -1:

1
2
3
4
1111 1110
+1111 1110
-----------
1 1111 1100 (多出一个进位1)

去掉溢出的1(符号之外)再加回最低位:

1
1111 1100 + 1 = 1111 1101

这是 -2 的反码。正确。

补码

现代计算机都用补码。

  • 正数:与原码、反码相同
  • 负数:反码+1
  • 好处:
    • 加减法可以用同一个加法器完成
    • 只有一个零
    • 范围可以多出一个负数(-128~+127 for 8-bit)
      例如:
十进制 原码 反码 补码
+5 00000101 00000101 00000101
-5 10000101 11111010(反码) 11111011(补码)
对于 n 位二进制:
  • 负数的补码 = $a^{n} - |X|$
  • 负数的补码再取补码(再求反码+1)就回到正数

如果要实现A-B时可以这样做:
A+(B的补码)
只要有一个加法器,就能同时完成加法和减法,因为:

  • B 为正:直接加
  • B 为负:加上它的补码

补码天然让溢出和进位处理一致。
📌 优点:无需单独的减法器/减法指令,只需:

  • 把第二个操作数取补码(硬件中通过反码+1实现)
  • 然后用同一个加法器执行加法

例 1:−1+−1(补码)
步骤

  • -1(补码)**:
    • 原码:1000 0001
    • 反码:1111 1110
    • 补码:1111 1111

两数相加:

1
2
3
4
1111 1111
+1111 1111
-----------
1 1111 1110

丢弃最高位的进位(溢出位):
1111 1110

→ 这是 -2 的补码(因为负数补码 = 反码 + 1 → 反码 = 1111 1101 → 原码 = 1000 0010)。
直接得出 -2
📌 补码不需要回加


例 2:2+(−3)(补码)
步骤

  • +2(补码):0000 0010
  • -3(补码)
    • 原码:1000 0011
    • 反码:1111 1100
    • 补码:1111 1101

两数相加:

1
2
3
4
0000 0010
+1111 1101
-----------
1111 1111

1111 1111 → 这是 -1 的补码
✅ 结果正确:2+(−3)=−1。