首先,对于这三个码,你是否是这样理解的?
- 原码是一个有符号数在计算机内的二进制表示,最高位是符号位,最高位是1表示负数,最高位是0表示非负数
- 正数的反码是正数本身,负数的反码是其原码基础上,符号位不变,其他位取反
- 补码=反码+1
如果你是这样理解的,那么读下去,这篇文章将对你大有好处
以上的理解不能说错误,但它只能算是速记口诀,它掩盖了补码真正的内涵,使得我们的理解浮于表面,对进一步学习产生极大困扰。
咱们言归正传,如何正确理解原码、补码、反码?
【以下全部以8位二进制来举例,涉及到的全都是有符号数】
1. 为什么要原码?为什么不止原码?
- 我们日常的计算不仅涉及加法,还有大量的减法,加减法作为基础运算,时刻发生在计算机中,加法运算十分简单,对计算机非常友好;减法运算在我们人类脑中只需要向高位借位即可,但是要理解“借位”,对于计算机可非常不友好。
- 统一加减法,更确切地说,使减法也能以加法的规则来计算,这样计算机就只用进行加法操作,大大提高计算效率。
- 思考:如何使减法以加法的规则来运算?
1) 这个问题我们熟悉,a-b=a+(-b)
2)那么加减法问题就转化成了正负数问题,有一个正数,就一定对应一个相反的负数,那么正、负数的个数应该是对半分,把2^8个数分为两半的方法就是,由最高位0开头的为一种,最高位1开头的为一种,这就是原码,原码包含符号位,最高位是1代表负数,最高位是0代表非负数。
3)最高位是符号位,这是我们规定的,我们知道00000001代表的数字是1,10000001代表的数字是-1,但是电脑可不认账,它还以为10000001表示的是2^7+1,所以必须再找到一种新的办法,使得符号位也参与运算,达到只保留加法的目的。
2. 思考:如果是你,你该如何去寻找这样的方法呢?
- 我们的难题是:如何使减法以加法的方式运行?
- 这个问题反着说:如何用加法的形式实现减法的效果?
我们中国人讲究中庸之道,因为“水满则溢,月圆则亏”,“若要让其消亡,必先让其膨胀”;我提这些都是为了启发你的思维,想必你一定有些思想苗头了,如果没有,再想想,时间不会倒流,那你手表上的时间为什么周而复始地会出现相同的时刻呢? - 是的,时钟现在指向6点,要想指向4点,我们可以把时针往回拨2小时(-2),但是我们也可以把时针往前拨动10小时(+10),当我们把8位二进制看做一个首位相连的时钟时,便能够以加法的方式来实现减法的效果。
- 为了便于理解,我们先延续上述时钟的12进制为例,-2被+10取代可以获得同样的效果,我们的先辈就定义10就是-2的反码,也就是用【12-2】来计算-2的反码表示。
- 我么回到8位二进制,这个特殊的时钟,【11111111】就是它的“12点”,对于负数-x,我们定义【11111111-x】来表示-x的反码(需要提示一下,x是正数),取正数a,这样便实现了:a-x=a+(11111111-x)
- 上一点是反码的核心定义与内涵,反码的外在表现形式就是“在原码基础上,符号位不变,其他位取反”,所以我说这顶多算一个速记口诀
- 心中时刻想着时钟(内在原理是取模运算),自然就能理解,我们将反码参与运算时,最高位产生的进位需要加到最低位,因为时钟都是“首位相连”的,这就是反码的运算规则,请牢记。
3. 思考:反码的解决方案你满足了吗?
-
想一想下列问题:
1)反码【00000000】和【10000000】代表什么数值?
2)用反码的运算规则,计算一下【01111110】-【00111110】,运算步骤要详细 -
揭晓答案:
1)【00000000】表示+0;【10000000】表示-0,我们知道+0和-0都是0,但这也的确是反码设计的一个瑕疵
2)反码运算规则实质上是轮盘式运算,模糊了起点和终点,产生的进位会导致二次计算,这是反码设计的另一个瑕疵
4. 针对反码的缺陷,你能寻找更好的办法来解决吗?
- 针对反码+0,-0的缺陷,我们首先要摒弃时钟周而复始的思想,因为时钟天然存在着首位连接的重叠问题。
- 针对反码二次计算的问题,我们要想办法让最高位不再进位;仔细想想,什么时候需要进位?例如,当计算机面对二进制【10000001】+【01111111】时,如果不进位,舍弃溢出的那一位,那么得到的结果就是【00000000】,请注意,“舍弃” 一词中包含有减法内涵。
事实是这样:原本最高位存在的【1】和加法进位而来的【1】相加,又产生新的进位,这个进位被舍弃,结果最高位变成【0】
但我们可以这样解释这个现象:原本存在的【1】和加法进位而来的【1】具有相反的属性,两者抵消,变成【0】,是不是很美妙? - 由此引出重要的概念:负权位 ,我们把8位二进制的最高位设为负权位,其他位都是正权位,这样就实现了上面所说的相反的属性;也就是最高位的权重是【-27】,其后各位的权重依次是【26】……【20】,习惯上,我们仍然沿用反码的叫法,也称最高位叫作符号位。
- 像这样,最高位是负权位,其他各位都是正权位的二进制码,其各位加和而来的结果为 x(正负均可), 我们称该二进制码为x的补码
例如:-3的补码是【11111101】,也就是-27+26+25+24+23+22+1=-3 - 那怎么计算负数的补码呢?按照定义来计算太麻烦了,还是以-3为例,补码之所以表现出来的真值为-3,是因为负权位比正权位多了3,那我们令-3的补码加3,其外在表现形式是归为【00000000】,但是我们心里清楚,其实是舍弃了溢出的进位,
也就是说 28= 3的补码表现形式+3,反过来【3的补码表现形式】=28-3
对于非负数x,我们用【2w-x】来计算-x的w位补码表示 - 你还记得-x的反码表示吗?没错是【11111111-x】,因此,在计算表现形式上,我们说补码=反码+1
- 这样补码【10000000】就代表-128;补码【00000000】代表0;这也就是为什么补码的取值范围是[-128,127],原码和反码的取值范围是[-127,127]
5. 总结
- 现代计算机,都是以补码的方式来运算的,来一个数字x,先根据正负转化成原码,若原码最高位是0,则补码就是其本身;若原码最高位是1,则最高位不变,其他位取反,得到反码,反码只是中间码,是为了得到补码,令反码+1,得到补码,再用补码来运算,计算机底层只需要做二进制的加法即可。
- 反码运算的思想是数学的模运算,是时钟周而复始的思想
- 补码运算巧妙利用了进位溢出,将舍弃进位理解为正负权位的抵消
写在最后:
文章不易,如果对你有用,请点赞支持,谢谢啦,你的支持是我最大的动力^V^

本文详细解析了计算机中原码、反码和补码的概念,重点讨论了如何通过加法实现减法,以及补码设计的初衷和克服原码反码问题的方法。通过8位二进制举例,讲解了负权位和补码运算规则,揭示了补码利用进位溢出的巧妙之处。
1777






