
文章目录
这里是think的博客
希望可以一起交流知识,一起think
今天我们来学习补码的相关知识/p>
一起来think吧
一、前言:计算机的“天生缺陷”——只会做加法
早期计算机的硬件设计非常简单,核心运算部件只有「加法器」,没有专门的减法器。这就带来一个问题:人类能轻松计算 5-3,但计算机只会加,不会减,怎么让计算机实现减法运算?
于是工程师们开始思考:能不能把减法转换成加法来做?比如 5-3,能不能等价成 5 + (-3)?答案是可以的,但关键在于——如何用二进制表示负数,才能让正数和负数直接相加,结果依然正确?
带着这个问题,人们先尝试了原码、反码,都失败了,最终才发现了补码的奥秘。
二、失败的尝试:原码和反码为什么不行?
在说补码之前,先简单讲一下有符号整数的表示规则:二进制序列的最高位是符号位,0表示正数,1表示负数,剩余位是数值位。
原码:直观但无法直接运算
原码的逻辑很简单:直接将数值按正负翻译成二进制。比如:
-
正数 1:0001(4位二进制,符号位0,数值位001)
-
负数 -1:1001(符号位1,数值位001)
看起来很直观,但当我们计算 1 + (-1) 时,问题就出现了:
0001(1) + 1001(-1) = 1010(二进制),对应的十进制是 -2,明显和预期的 0 不符。
原因:原码的符号位无法直接参与运算,需要单独判断正负、计算绝对值,逻辑复杂,无法满足“直接运算”的需求。
反码:解决了部分问题,但仍有缺陷
反码的规则:符号位不变,数值位按位取反。比如:
-
正数 1:0001(反码和原码相同)
-
负数 -1:原码1001 → 反码1110(符号位1不变,数值位001取反为110)
再计算 1 + (-1):
0001(1) + 1110(-1的反码) = 1111(二进制),对应的反码是 -0(符号位1,数值位111取反为000,即0)。
虽然结果接近,但出现了“+0”和“-0”两个零,逻辑上很别扭,而且运算仍有局限,无法满足所有场景。
三、补码的发现:从钟表类比到模运算
原码和反码的失败,让工程师们陷入困境,直到有人从生活中的「钟表」得到灵感——这就是补码的核心来源:模运算。
生活类比:钟表里的“减法变加法”
我们先看一个简单的生活场景:假设现在是3点,想调到1点,有两种方法:
-
减法:往回拨2小时 → 3 - 2 = 1
-
加法:往前拨10小时 → 3 + 10 = 13,钟表一圈只有12小时,超过12的部分自动“丢掉”(这是钟表自动丢的),最后还是1点
这里的关键的是:减去一个数,等价于加上这个数的“补数”,而“补数”的计算规则是:补数 = 一圈的总数 - 这个数。
钟表一圈的总数是12,我们称之为「模」(mod),所以2的补数就是 12 - 2 = 10,这就是为什么 3 - 2 = 3 + 10(mod 12)。
[我们完全可以看看我们的手表,时钟,看看从三点到一点的顺着和逆着是否构成了一圈?]
类比到二进制:固定位数的“二进制钟表”
可以把所有位数的二进制都类比位一个钟表,他们的性质完全相同。
计算机中的二进制是有固定位数的(比如4位、8位、32位),这就像一个“二进制钟表”,有固定的“模”:
-
4位二进制:能表示 0000~1111,共16个数字,模 = 16
-
8位二进制:能表示 00000000~11111111,共256个数字,模 = 256
回到我们最初的问题:5 - 3,用二进制怎么用加法实现?
按照钟表的思路:减去3(往会拨3),等价于加上3的补数(模16 - 3 = 13)(往前拨16-3)。
用4位二进制表示:
-
5 → 0101
-
13 → 1101
计算加法:0101 + 1101 = 10010(二进制),结果是5位,但4位二进制“装不下”第5位,这部分就会自动丢掉,剩下 0010(十进制2),和 5-3=2 的结果完全一致!(这里也是自动丢掉,为什么刚刚好丢掉以后就有了正确结果呢?,我们四位二进制可以表示0~15的数字,一共就16个数字,所以类比到钟表的12,4位二进制的一圈就是16,那么4位二进制是怎么自动丢掉一个16的呢? 其实是因为4位的二进制最大的数就是15,如果成了16就要进位了,而现在就是只有4位,那么第5位就无法存下,那么就只能丢掉了,这就是自动丢掉的逻辑)
- 由此我们看到二进制完美符合钟表的逻辑,就是可以自动丢掉多余的数,那么这样就可以用钟表逻辑将-化为+(本来就是只要能证明二进制可以将多余位丢掉,就可以将-化为+)
补码的本质:二进制中的“补数”
我们再看13的二进制(1101),它和-3的关系:
-3的原码是 1011(符号位1,数值位011),将原码的数值位取反(011→100),再加1(100+1=101),得到 1101——这就是-3的补码!
由此我们得出结论:负数的补码 = 模 - 负数的绝对值,而在二进制中,这个过程刚好等价于「原码取反 + 1」。(这个就是尝试出来的了,很好整的,就不严谨证明了)
四、关键疑问:为什么会“自动溢出”?
上面讲过了,现在系统讲一下。
很多人会疑惑:为什么丢掉高位(自动溢出)后,结果依然正确?其实这不是“神奇效果”,而是硬件设计和模运算的自然结果。
核心原因:计算机的整数是固定位数的,没有多余的空间存放超过位数的高位,就像钟表只能显示0~11,超过12的部分会自动“归零”一样。
以4位二进制为例,模是16,当运算结果超过16时,丢掉最高位(相当于减去16),本质就是“取模16”,而补码的设计本身就基于模运算,所以丢掉高位后,结果必然正确。
五、总结:补码能直接运算的核心逻辑
补码不是凭空发明的,而是工程师们为了解决“计算机只会加法”的问题,从生活中的模运算(钟表)得到灵感,逐步探索出来的,其核心优势的在于:
-
统一加减法:将减法转换成“加法+负数的补码”,让计算机只用加法器就能完成所有整数运算;
-
符号位参与运算:补码的符号位可以和数值位一起直接运算,不用单独处理,简化硬件逻辑;
-
自动溢出适配:固定位数的二进制自动丢掉高位,等价于取模,刚好契合补码的模运算逻辑,确保结果正确。
最后用一句话概括:补码就是“二进制钟表”里的“补数”,把负数转换成模内的等价正数,让减法变成加法,从而实现直接运算。
结尾
如果看到这里,你还是有点懵,建议结合具体的4位二进制运算(比如1+(-1)、3-2),一步步手动计算原码、反码、补码的运算过程,就能直观感受到补码的神奇。
计算机底层的很多设计,都源于生活中的简单逻辑,只要找对类比,就能轻松理解。如果本文对你有帮助,欢迎点赞收藏,关注我,一起解锁更多计算机基础知识点~

4044

被折叠的 条评论
为什么被折叠?



