计算机中的原码、反码和补码

1. 前言

我们知道,现代计算机主要采用数字集成电路搭建,数字电路通过高低电平只能表示0和1,所以计算机只认识0和1。无论是存储还是计算,计算机均采用二进制系统完成。例如:十进制的5用二进制表示为101

机器数
数字在计算机中的二进制表示形式叫作「机器数」。机器数有两个特点:
1、机器数是带符号的,即分正负。最高位0代表正数,1代表负数。
2、二进制位数受设备限制,字长8位叫一字节,机器字长一般是字节的整数倍,例如:32位、64位。
例如机器字长为8的情况下,十进制的5机器数表示为00000101,-5机器数表示为10000101

真值
因为第一位是符号位,所以机器数的形式值不等于其真值。例如上述10000101,真值为-5,二进制的形式值却是133。因此,将带符号位的机器数对应的真正数值称作机器数的真值。

2. 原码反码补码的概念

计算机直接使用二进制就好了,为啥要区分原码、反码和补码?在探究这个问题前,不着急,先了解一下它们的概念和计算规则。

1、原码:符号位+真值的绝对值。

 5 = 00000101()
-5 = 10000101()

2、反码:正数的反码是它本身;负数的反码除符号位外,其余位取反。

 5 = 00000101()
-5 = 11111010()

3、补码:正数的补码是它本身;负数的补码是它的反码+1。

 5 = 00000101()
-5 = 11111011()

3. 演进过程

已经有原码了,为什么还要用反码和补码呢?是不是多此一举?非也!

对于计算机而言,实现加法器相对简单,相反减法器就略显复杂,需要考虑借位等逻辑。早期的计算机是有减法器的,后面因为效率太低慢慢被废弃了,能否设计一种编码,让符号位也直接参与运算呢?这样只需要加法器就可以同时完成加减法计算了,电路的设计会更加简单和高效。

3.1 原码的缺陷

使用原码直接进行运算,对于加法是没有问题的,例如5+5=10。

 00000101()
+00000101()
=00001010
=10D

原码最大的问题是,无法将减法转换为加法。例如3-2,我们可以通过计算3+(-2)得到结果,原码的计算结果是-5,明显是错误的。

 00000011()
+10000010()
=10000101()
=-5D

3.2 反码的瑕疵

反码的出现正是弥补了原码无法执行减法运算的问题,反码运算减法的规则:A-B=A+(-B),如果最高位发生了进位,则需要低位再加1。

还是拿上面的3-2的例子,反码的计算过程如下,最终结果为1。

 00000011()
+11111101()
=100000000+1(最高位溢出)
=1D

反码的计算结果是对的,但是算法规则稍微有点复杂,需要考虑最高位溢位的情况,效率偏低,另外还有一点瑕疵:0有两种编码。

以1-1为例,反码的计算过程如下,结果为-0,其实也就是0。我们发现,在反码中,0000000011111111都表示0,0有两种编码,在判断是否为0时需要判断两种编码,算是一点小瑕疵。

 00000001()
+11111110()
=11111111()
=-0D

3.3 补码的完美

补码是现代计算机使用的编码格式,同时解决了原码的缺陷和反码的瑕疵。

首先,补码是可以将减法转换为加法的,以3-2为例,计算过程如下,结果正确。

 00000011()
+11111110()
=100000001()最高位溢出,直接丢弃
=00000001()
=1D

其次,0不再有两种编码了,还是以1-1为例,计算过程如下,0只有一个编码,那就是00000000。既然00000000代表1,那11111111代表什么呢?此时人为的规定它就是-128D,所以使用补码,1个字节的表示范围是[-128,127],比反码还多了一个数值。

 00000001()
+11111111()
=100000000()最高位溢出,直接丢弃
=00000000

综上,我们发现,补码不仅可以将减法转换为加法,而且算法规则也更加的简单,不需要考虑最高位溢位的情况,发生溢位直接丢弃即可,计算效率也更高,而且补码还解决了反码中0有两种编码的问题。

反码和补码的计算过程并不复杂,但是要理解为什么还可以这么计算,就需要去了解这里面涉及到的数学知识了。

4. 补码的奥秘


首先,大家了解一下「模」的概念。任何计数系统都必须有两个参数:容量和精度,模就是衡量计数系统中容量的参数。我们以时钟举例,大家把12看作0,假设时间从0点开始。当时针转到11的时候,再往后转就没有12了,又重新回到了0,开始新的轮回,那么12就是时钟的模。
image.png
计算机系统同理,字长为8字节的机器,它最大能表示的值就是11111111,则它的模是256。

模N加减法
在有「模」的前提条件下,当我们要计算减法时,我们其实有两种计算方法。以时钟为例,模M=12时,计算8-6的方式一是将时针正常往回拨6小时,得到2。方式二是将时针往前拨6小时,得到的结果也是2。

于是,我们可以得出这么一条结论,A-B = A+(M-B),+M相当于时针拨了一圈,并不影响结果,但是却可以将减法转换为加法。有的同学可能会有疑问,M-B不还是减法嘛,是的,但是这种减法不需要减法器即可实现。M-B称为-B的补数,计算一个数的补数,并不需要减法。

我们以4比特字长为例,最大值为1111,即模M=16。计算5-3,其实和5+16-3=5+13的结果是一样的。我们发现3和13互为补数,其它补数还有例如2和14、1和15等,我们发现A-B等于A+B的补数,B的补数如何不通过减法快速求得呢?
3的补数由16-3计算而得,我们拆解一下这个公式,16-3=15-3+1,15二进制的表示四个位全是1,1111-0011其实就是0011自身取反得1100,最后再+1得1101=13D就是它的补数。

模N加减法实现了「化减为加」,但是还有个问题,没有区分正负数。人们在计算时是需要考虑正负数的,所以就需要人为的将一部分二进制划分为负数,一部分二进制划分为正数。当模M=16时,根据公式A-B=A+16-B,当A为零点时,-B=16-B,即时针逆时针移动B,也可以由顺时针移动16-B得到。零点A可以是00001111中的任意一个数,为了方便计算,人为规定0000为零点,那么0001为+1,1111为-1,1110为-2,以此类推,结果都是符合补码定义的,大家可以算一下。

5. 总结

现代计算机采用数字集成电路搭建,通过高低电平来表示0和1,所以计算机均采用二进制系统完成。二进制只有0和1,无法表示符号,即正负数,因此人们定义了原码,最高位0代表正数,1代表负数。同时,计算机为了简单和高效,只有加法器,没有减法器,原码最大的问题是不能把减法转化为加法,所以有了反码。反码可以「化减为加」,但它的效率不高,需要考虑最高位溢位的情况,算法相对复杂,且0存在两种编码,有一定的瑕疵,最终,才有了现在的补码。补码同时解决了原码和反码的问题,采用模N加减法,不需要考虑最高位溢位的情况,遇到溢位直接丢弃,效率非常高。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小潘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值