首页 > 编程知识 正文

原码 反码 补码 移码详解,原码反码补码例题详解

时间:2023-05-04 00:51:43 阅读:220532 作者:2418

【计组笔记-6】详细分析原码,反码,补码,以及移码 1. 原码2. 模运算3. 反码&补码4. 移码5. 总结

1. 原码

原码是有符号定点数的一种编码方式,规定了最高位为1代表负数,为0代表正数,数值位是数据的二进制真值。具体来说,又分为原码整数与原码小数,其中,原码整数的小数点默认在最低位的右边(隐式存在),原码小数的小数点默认在符号位的右边(隐式存在),此外,原码整数是在高位补0,而小数是在低位补0。

例如,-3的原码(4bit)为1011,-0.75的原码(4bit)为1.110。要注意的是,计算机内储存的二进制数是不存小数点的,小数点都是隐式存在的,书面表达时会标注小数点是为了方便理解。

然而,虽然原码规定了正数与负数,整数与小数的储存方法,但我们无法统一的用加法器对它们进行运算,例如(均用加法器):

两正数相加:0110 (6) + 0011 (3) = 1001(9) √两负数相加:1110 (-6) + 1011 (-3) = 11001(25)x正与负相加:1110 (-6) + 0011 (3) = 10001(17)x

综上,可见,用加法器是无法实现对负数原码进行计算的。那么,是否用减法器就能解决问题了呢,我简单查阅了一下资料。

补充:为什么没有减法器?

以下引用自百度百科:

ALU必须与数字电路的其他部分使用同样的格式来进行数字处理。对现代处理器而言,数值一律使用二进制补码表示。早期的计算机曾使用过很多种数字系统,包括反码、符号数值码,甚至是十进制码,每一位用十个管子。 以上这每一种数字系统所对应的ALU都有不同的设计,而这也影响了当前对二进制补码的优先选择,因为二进制补码能简化ALU加法和减法的运算。 一个简单的能进行与或非和加运算的2位ALU。

可见,当下用补码作为数值的二进制储存方法,并用加法器来实现减法运算,不是一蹴而就的,也是慢慢发展而来,最终由于这种方法实现较为简单而被采用。

又简单搜了一下,更精简的算术逻辑单元似乎可以使cpu主频更高,但有待考证,先写在这里。

2. 模运算

通过上面的分析,已知当前cpu里没有减法电路了,那么如何用加法器来实现减法呢?先说结论:用补码。但在介绍反码和补码之前,想要先简单介绍一下模运算。

想象一下,在角度里,如果想要表示第一象限里的30°,则既可以描述为+30°,又可以描述为-330°,且任何一个度数加上或减去360°都可以认为角度没有变化(只是转了一圈)。

在上面的例子里,可以称30°与-330°进行模360°运算时,余数是一样的,均为30,因此,可以理解为,30和-330在运算时是等价的。即x-330,与x+30是等价的。通过这样的方式,就可以把减法转换为加法进行运算。

在二进制数里,由于位数有限,且溢出的部分会被丢弃,因此,也导致了这样的现象,以大小为4bit的数为例,它可以存的最大值是24-1即15,而15+1时,储存的二进制数就变回了0,(因为最高位的1超出了4位,被溢出截断了),它就像24小时或者360°一样,也有一个范围限制。

因此,同样可以通过对这个范围进行模运算,求出与负值等价的正值,来将减法转变为加法。例如,3-1=2(0010)可以改写为3+15=18(10010,截断最高位的1后也是0010),而-1模24的余数与15模24的余数是相等的,都是15,因此,它们可以被视为等价。

其实,讲的再通俗易懂一点,任何一个数加上10000(二进制),都不会改变它的大小,因为一个限定为4位的二进制数会把10000视作0,就像,任何一个角度加上360度,它的最终朝向都不会有变化一样。

因此,一个包含负数的表达式,后面无论加上多少个10000,或者360°,大小都不会有变化,基于该显而易见的理论,就可以更简单的理解为什么3-1=3+15,因为3-1+24=3-1+0=3-1。

而要计算与一个负数等价的正数,也可以简单的将这个负数与最大范围相加,直到出现正数为止,例如-330°+360°=30,因此,30°与-330°等价。

理论推导和数学定义就不写了,贴一个视频在这里,感兴趣的可以自己看下:计组网课p15,主要是简单理解下通过模运算是将减法转为加法的根基。

3. 反码&补码

上一小节分析了如何将减法转为加法,还是以4位二进制数为例,-1的原码是1001,与-1等价的正数是-1+24=15(1111),因此,如果能够通过一种方式,将负值的原码转为等价正值的原码,那就可以用加法器计算减法了,而这个所谓的等价正值的原码,就是补码

分析一下如何得到补码,还是以4位为例:

设x为一个负数的原码,最大范围是24,补码为y,则x+24=y,这里只加24即可,是默认了x<24,如果它超过了这个值,那也无法被只能容纳4位的数据类型储存。

已知y为所求,x+24=y,y-x=24=10000=1111+1,1111=y-1+(-x),设y-1=z,则可整理出表达式为:z+(-x)=1111,其中,由于x为负数,因此-x为正数,即在x的原码基础上,将最高位改为0。

显而易见,z的求法,是将-x的原码按位取反,例如,0110+1001=1111,0110和1001是按位取反的关系,又已知-x跟x在原码上的区别只是最高位,因此,也可以说,z=x除最高位外按位取反而z就是反码

又已知z=y-1,因此,y=z+1,即补码等于反码加1

此外,正数的反码和补码跟原码都是一样的,因为首先,与它等价的其余正数都超过4位能容纳的最大值了,其次,补码本身就是针对负数的。

综上所述,补码的出现,是为了将减法统一为加法,而补码的计算方法是基于模运算的理论,此外,反码是计算过程中的一个中间值,一般不直接参与计算。

4. 移码

移码的出现,主要是为了在硬件层面方便对比两个数的大小,它常见于储存浮点数的阶数。

简单来说,在整数相加的过程中,只要直接计算即可,但是浮点数相加的过程中,有一个对比阶数的过程,用10进制举例,3.2x1012+1.5x1010=3.2x1012+0.15x1012=(3.2+0.15)x1012,最后的阶数是12,即12和10中的较大值,可见,在浮点数计算过程中,有一个阶数对比的步骤。

补:为什么不统一为阶数的较小值呢,因为浮点数中数值位是一个定点小数,小数点永恒定在开头,如果统一为较小值,就变成了(320+1.5)x1010,数值位的小数点就不是永远定在开头了,而是会变化,显然不方便机器层面的运算。

综上,得到优化目标为:加速阶数的大小对比。

已知数值都是用补码储存的,从小到大列出4位二进制数的补码如下:

真值补码移码-810000000-710010001-610100010-510110011-411000100-311010101-211100110-111110111000001000100011001200101010300111011401001100501011101601101110701111111

观察一下就能发现,如果按照01234567,-8,-7,-6…-1这个顺序来看补码,刚好是将补码从小到大的排序!因此,只要将补码稍稍“移动”一下,就能得到可以很简单的对比大小的移码

补:为啥说移码对比起来简单呢,举个例子,0111和1010比大小,从左到右遍历,先出现1的就更大,如果同时出现了1,那么下一个先出现1的就更大。所以其实移码就是,把补码移动一下,变成n位二进制数从小到大排列而已。而这个“移动”的过程,需要加上一个值,这个值就叫偏置值

上述这种,移码的0从n位二进制数的最小值开始的情况,的计算方法是补码+2n-1,分析一下,要从上表的补码变成移码,就像捏着补码的0000,往上提8(2n-1,负数的最大值的绝对值)个格子,往上提1个格子的话,真值0对应的移码会变成0001,即0000+1,因此,提2n-1个格子,对应的计算方法就是补码+2n-1了。

而补码=真值+2n,因此,移码=补码+2n-1=真值+2n+2n-1=(真值+2n-1)+2n,也就是说,偏置值2n-1直接作用于真值也是可以的,此外,由于-2n-1是n位二进制数的最小值,因此真值一定≤2n-1,(真值+2n-1)一定≥0,因此,+2n就等于+0(正数的补码等于原码)。

因此,综上所述,如果手动计算移码的话,把真值+偏置值的结果直接转成二进制原码就行了

然而不一定所有移码的0都是从n位二进制数的最小值开始,如float类型里阶数的移码形式,0是从-127开始的,它把-128和-127这两个状态单独扣出来有特殊用处,这就是按照不同需求,设置不同的移码实现方式了。

5. 总结

补码的出现,是为了用加法器实现减法运算,而移码的出现,是为了使得两个有符号整数对比的更快速,而现在常用的计算这两个码的方法,如补码是原码除最高位外取反+1,移码是真值+偏置值,这是基于理论推导后得出的等价算法,不那么好理解,但算起来很简单。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。