☰
原码反码补码移码取值范围详解:为什么补码能表示-128
2026/10/14 1:19:15 网站建设 项目流程

先问一个几乎所有计算机专业学生都问过的问题:为什么八位二进制,原码只能表示到127,而补码却能多表示一个-128?别急着说“因为原码有两个0”,这个答案只对了一半。完整理解四种码制的取值范围,关键在于搞清楚每种码制在编码空间里到底“浪费”了多少个状态,以及这些状态为什么会被浪费。这篇文章我会直接从机器数的概念讲起,逐步推导四种码制的取值范围,再结合考场上真正会出现的题型和常见陷阱,把这块硬骨头一次性啃干净。

这篇文章适合正在复习计算机组成原理或者数字逻辑的在校同学,也适合准备考研408或者面试计算机基础的开发者。只要你需要在短时间内把原码、反码、补码、移码的取值范围和互相转换搞到“一眼看出答案”的程度,这文章就是给你写的。

1. 机器数与四种码制:先建立完整认知框架

1.1 符号数值化是理解一切的前提

计算机里只有0和1,所以“正号”和“负号”也必须用0或1来表示。把符号位放在最高位,剩下的位用来表示数值大小,这种带有符号的二进制数就叫机器数。这里必须建立一个关键概念:我们讨论的“机器字长”,比如8位、16位,永远是包含符号位在内的总位数。

  • n位机器数,其中最高位是符号位,0代表正,1代表负;
  • 剩下n-1位是数值位,用来表示绝对值的二进制形式;
  • 一个机器数对应的真实带符号数值,称为真值。

为什么要搞出四种码制?因为光有原码不够用。原码虽然直观,但做加减法太痛苦:加法要判断同号还是异号,减法要处理借位和符号,硬件实现极其繁琐。后来人们发现,如果把负数用一种特殊方式编码,可以让“减法”变成“加法”,整个运算电路统一成加法器,速度和成本立刻优势明显。这就是补码出现的最直接原因。

反码是个过渡产物,它的存在价值有两点:第一,反码加一可以得到补码,所以求补码的过程依赖反码;第二,在一些老式电路或特定运算规则里,反码有自己独特的运算处理方式。移码则完全是为浮点数阶码比较大小而生的,它的好处后面会专门讲。

1.2 四种码制的定义与转换关系

先给结论,再讲原理。假设真值x,机器字长n位:

原码:符号位加真值的绝对值。

  • 正数:符号位0,数值位是x的二进制;
  • 负数:符号位1,数值位是|x|的二进制。
  • 4位例子:+7 = 0111,-7 = 1111。

反码:正数的反码等于原码;负数的反码是在原码基础上,符号位不变,数值位逐位取反。

  • 4位例子:-7的原码1111,反码1000。

补码:正数的补码等于原码;负数的补码是反码加一,即数值位取反后在最低位加1。

  • 4位例子:-7的反码1000,加一得到1001,所以-7的补码是1001。

移码:不管正负,直接在补码的基础上把符号位取反。

  • 4位例子:-7的补码1001,符号位取反得到0001,所以-7的移码是0001。

这里有一个非常实用的转换链:原码 → 反码 → 补码 → 移码,每一步都是一次固定操作,从右往左做可以逆推回来。

提示:负数原码转补码还有一个更快的技巧——从右往左找第一个1,这个1左边的所有数值位取反,符号位不动,右边保持不变。比如-25的原码10011001,从右往左第一个1在最低位,所以数值位除了这个1以外全取反,得11100111。这个技巧考试时能省很多时间。

2. 取值范围推导全过程:补码为什么多一个数

2.1 从4位二进制推起,把编码空间看成一间屋子

n位二进制一共能组合出2^n个不同的编码。关键问题在于:这些编码中有多少能对应到“合法真值”?有多少被浪费了?

以4位为例,一共16个编码,0000到1111。我们看四种码制分别怎么分配这16个编码:

二进制编码原码真值反码真值补码真值移码真值
0000+0+00-8
0001+1+11-7
0010+2+22-6
0011+3+33-5
0100+4+44-4
0101+5+55-3
0110+6+66-2
0111+7+77-1
1000-0-7-80
1001-1-6-71
1010-2-5-62
1011-3-4-53
1100-4-3-44
1101-5-2-35
1110-6-1-26
1111-7-0-17

观察这张表,能读出几个重要信息:

第一,原码和反码在“0”上都浪费了两个编码。原码有0000和1000两个0,反码有0000和1111两个0。原本16个编码可以表示16个数,结果只表示了15个不同的数。

第二,补码只有一个0,0000就是0,没有任何编码表示-0,所以省出来的那个编码1000给了-8。这就是补码取值范围比原码、反码多一个数的本质原因。

第三,移码的值范围与补码完全相同,只是符号位取反后对应的数整体偏移了。

2.2 通用公式:n位机器数四种码制的取值范围

把4位的情况推广到n位,直接上公式,这些公式必须背到条件反射:

原码取值范围:-(2^(n-1)-1) 到 +(2^(n-1)-1)。数值位能表示的最大绝对值是n-1位全1,即2^(n-1)-1,正负各一份,中间是正0和负0。

反码取值范围:与原码完全相同,-(2^(n-1)-1) 到 +(2^(n-1)-1)。两个0的问题同样存在。

补码取值范围:-2^(n-1) 到 +(2^(n-1)-1)。最小负数对应的编码是1000...0(1后面n-1个0),最大正数对应的编码是0111...1(0后面n-1个1)。

移码取值范围:与补码相同,-2^(n-1) 到 +(2^(n-1)-1)。但移码编码与真值的对应关系整体偏移,后面会展开。

我建议你把8位和16位两个具体数值记住,考试直接套:

  • 8位原码/反码:-127到+127;
  • 8位补码/移码:-128到+127;
  • 16位原码/反码:-32767到+32767;
  • 16位补码/移码:-32768到+32767。

2.3 补码统一加减法的背后:模运算

前面说的是“形状”,这里补一下“为什么”补码能多表示一个负数的数学根因。

补码的严格定义是:对于n位二进制,模M = 2^n,负数x的补码等于M + x。这个定义和“取反加一”是等价的,只是看起来更抽象。为什么要加一个M?因为计算机里的运算都是对M取模的,超过M的进位自然丢弃。

举个生活例子你就懂了:时钟一圈12个小时,这就是模12系统。现在是10点,要拨到2点,可以顺时针拨4个小时(10+4=14,模12等于2),也可以逆时针拨8个小时(10-8=2)。在模12系统里,+4和-8是等效的。所以负数-8可以用正数+4来表示,这就是补码思想。

对应到4位二进制,模M=16。要表示-8,用16+(-8)=8,二进制就是1000。要表示-7,用16+(-7)=9,二进制1001,正好就是“取反加一”算出来的结果。这个模运算视角还能解释为什么-128没有原码和反码:-128在8位下绝对值是128,需要8位数值位才能表示,但8位机器数只有7位数值位,放不下。而补码用模运算,-128的补码是256-128=128,也就是10000000,恰好在这个8位编码空间里。

3. 高频考点分类拆解:看到题目先想到这三条路

3.1 考点一:给定机器字长,求各码制取值范围

这个考点最直白,直接套公式。但有几个变形容易丢分:

题目可能不直接给“机器字长”,而是说“字长8位,其中一位符号位”,还是同样的意思。有些题目会说“用8位二进制表示一个带符号数,它的补码范围是多少”,答案都是-128到+127。注意这里的“8位”是含符号位的整体,不是数值位。

还有一种考法:给出n位补码的最小负数,然后问它的十进制值。答案就是-2^(n-1)。比如8位补码10000000对应-128,16位补码1000000000000000对应-32768。

3.2 考点二:真值转机器数,重点是负数链条

这类题要求给定真值,分别写出原码、反码、补码、移码。我先带一个完整例子,机器字长8位,真值-25。

第一步,写出原码。25的二进制是0011001(7位),加上符号位1,原码是10011001。

第二步,求反码。符号位不变,数值位取反:11100110。

第三步,求补码。反码加一:11100111。

第四步,求移码。补码符号位取反:01100111。

整个过程一分钟内完成,熟练后甚至可以不用纸笔。这里要注意:移码是在补码基础上取反符号位,不是在真值上加偏置量再加符号位,虽然两种理解结果一致,但在“给定真值直接求移码”时,先求补码再取反是最快的。

如果题目给的是正数,那更简单,四种码制(移码除外)的前三位都一样,只有移码符号位会变成1。比如+25,原码、反码、补码都是00011001,移码是10011001。

3.3 考点三:机器数转真值,警惕负数和移码

这个方向的考点容易在“认符号”上出错。

如果给补码求真值,先看符号位。符号位0,直接转十进制;符号位1,说明是负数。求法:把补码减一得到反码,再取反得到原码,读出绝对值,加负号。快捷方法:从右往左找第一个1,这个1左边(除符号位)全部取反,得到的就是原码的数值位。比如补码11110011,从右往左第一个1在最低位,所以数值位直接全部取反得0001100,再加上符号位1,原码是10001100,真值-12。

如果给移码求真值,最稳妥的方法是把符号位取反变成补码,再按补码求真值。比如4位移码1011,符号位取反得0011,这是补码,符号位0,真值+3。不要试图直接解读移码编码,除非你对偏置量公式非常熟。

3.4 考点四:补码运算与溢出判断

补码的另一个必考点是加减法运算结果溢出判断。补码的n位范围是-2^(n-1)到2^(n-1)-1,运算结果超出这个范围就溢出。

两个正数相加,符号位变成1,必然溢出。比如4位补码中,7+1:0111+0001=1000,结果符号位是1,而正正相加不该得到负数,溢出。

两个负数相加,符号位变成0,必然溢出。比如4位补码中,(-7)+(-8):1001+1000=10001,丢掉最高进位后是0001,结果是正数,这明显是错的,溢出。

一正一负相加,补码运算本身不会溢出,因为结果绝对值一定小于等于两个数中绝对值较大的那个,落在范围内。

还有一种判断方法是双符号位法:运算结果的两个符号位不一致就溢出。这个方法在组成原理大题里经常出现,但针对“取值范围”这个小专题,你只需要掌握第一种“结果落在范围外即溢出”的思路就够了。

3.5 考点五:移码为什么适合做阶码

浮点数的阶码用移码表示,核心原因是:移码编码的二进制大小顺序和真值大小顺序完全一致。

拿4位移码看:真值-8对应编码0000,-7对应0001,一直到+7对应1111。如果直接把这四个编码当作无符号数比较,0000 < 0001 < ... < 1111,从小到大排列正好对应真值从小到大。这意味着硬件上做阶码大小比较时,不关心符号位,直接按无符号数比较就行,逻辑电路极其简单。

如果用补码做阶码,负数编码(符号位1)在无符号比较下会排在正数前面,硬件必须额外判断符号位,多一步逻辑,速度就慢了。这就是移码存在的意义。

考试如果问“为什么浮点数阶码用移码表示”,这三句话就是满分答案:单调性、无需额外符号判断、便于硬件比较。

4. 易错点与避坑实录:改作业时最常见的错误

4.1 把“n位数”当成“n位数值位+1位符号位”

这是全专业最经典的一个错误。题里说“某机器字长8位”,意思是总共8位,其中1位符号位,7位数值位。如果理解成8位数值位再加1位符号位,等于9位,取值范围全部算错。只要看到“字长n位”,永远记住:n已经包含符号位。

我见过最离谱的错法是:8位补码范围算成-256到+255。问了一下,对方把8位全部当成数值位,又额外加了一个符号位。如果你也有这个习惯,先从概念上纠正:8位总共就那么8个二进制位,符号位占据最高位,剩下7位是数值位。

4.2 原码和反码的“负零”分不清

原码的负零是1000...0,反码的负零是1111...1。这个不但会考表示,还会在判断“哪种码制零的表示唯一”时出现。

答案:补码和移码的零表示唯一,都是0000...0(移码是补码符号位取反,所以00000000的移码是10000000,但那也是唯一的零)。

有一个常考延伸:既然原码、反码有正零负零,那么它们在数值比较时会出问题吗?理论上是会的,原码中+0和-0是不同编码,如果硬件用原码做相等判断,会遇到“同一个数两种表示”的困扰,这也是补码最终胜出的原因之一。

4.3 负数补码“取反加一”时在最低位加一,别加到符号位

这个错误很隐蔽。比如-5,8位。5的二进制00000101,取反11111010,加一得到11111011。注意这里加一是加在最低位,不是符号位。数字逻辑课有同学不知为什么加到了符号位,得到01111011,那是正的123,完全错了。

“取反加一”的加一,加的是整个数的二进制值加一,也就是最低位加一,如果最低位是1则进位。这个进位可能导致中间某些1变0、0变1,但符号位不会变。因为负数补码的数值位不可能全部是1,反码加一最多影响到数值位。

4.4 移码与补码的符号位恰好相反,别绕进去了

移码 = 补码符号位取反,这个关系是最简洁的记忆方式。但考场上容易把“移码”和“原码”搞混,因为负数移码看起来像正数原码,正数移码看起来像负数原码。可以这样绕出来:看到移码,第一步永远先符号位取反变成补码,再做后续计算。不要尝试直接解读移码,也不要记忆“移码是补码的值加偏置量”这种复杂定义,就一条路:先变补码,再走补码流程。

4.5 表格化的常见问题速查

问题症状可能原因纠正方法
8位补码范围算出-256到255把字长理解成数值位记住n含符号位
认为原码只有一个零忽略1000...0记住原码、反码有两个零
负数补码转真值结果差1忘了减一先于取反先减一再取反
移码转真值直接按原码读忽略符号位取反先转补码再真值
-128的原码写不出来很慌这是正常的8位原码范围不含-128
溢出判断只靠进位应该看结果是否在范围用符号位变化判断

5. 备考建议与速记口诀:一个老教师的三个土办法

5.1 土办法一:写一个小编码表在草稿纸上

考试一拿到草稿纸,先别急着做别的,花三十秒把4位机器数对应的原码、反码、补码、移码表默写出来。不要小看这张表,它涵盖了所有取值范围的推导基础,也包含了大多数转换题所需的核心编码。默写的方法是把上一篇文章里那张表从0000到1111按顺序列出来,补码那一列自然呈现-8到+7的完整序列。

这个方法为什么有用?因为很多人背公式记不住,但从0000开始逐个编码写下来,你会发现规律:补码那一列,从0000到0111是0到7,从1000到1111是-8到-1,顺序是连续的。原码那一列,1000是负零,和正零0000之间缺了一个数,所以取值范围少了。这种“从现象中悟规律”的记忆方式比死记硬背牢得多。

5.2 土办法二:用“时钟”和三句话理解补码核心

你不需要在考场上写出模运算的完整证明,但你需要用时钟模型在心里快速定位“补码为什么是这个值”。只要记得:n位补码,模是2^n,负数补码等于这个模加上真值,那么-1的补码永远是全1,-2^(n-1)的补码永远是1000...0。这两个特殊值几乎每年必考,记下来做题快得多。

三句话总结:

  • 所有负数补码的最高位都是1;
  • 补码减一得到反码,反码取反得到原码;
  • 补码的取值范围比原码多出来的那一个,恰恰是最小负数。

5.3 土办法三:考前集中训练“秒答”题

取值范围和码制转换这类题,本质是熟练工。我建议考前每天早上花十五分钟,拿一张纸,随机写一些负数,比如-37、-86、-13,然后限时三十秒内写出它们的四位码。连续十天,你的速度会快到草稿纸都不用。

为什么用负数练?因为正数的四种码基本一样,难度低。负数才是考试拉开差距的地方。练完转换,再练“看到补码读出真值”,比如随机写11101011、10000001,要求一秒内反应它是-21、-127。要是这个速度达到了,考场上原码/反码/补码/移码的取值范围和转换题就是送分题。

我个人教了这么多年,最深的一个体会是:这个topic把“符号位”和“数值位”当做一个整体来看待,比先拆开再组装的方式容易理解得多。很多学生反复出错,根源就在于把那1位符号位当成附加的东西,而实际上它在编码空间里占据了一个固定的位置,四种码制的差异全部围绕这个位置展开。顺着这个思路,再回看那个“为什么补码能表示-128”的问题,你会发现答案异常清晰:不是补码“多”了一个数,而是原码和反码在零上“浪费”了两个编码,补码把浪费掉的编码回收利用,用在了最小的负数上。想通这一点,后面所有计算都顺了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询