补码的形成与本质

补码,正数原补码相同,负数是把正数的原码取反再+1。

这是数字逻辑的规定,大家都要遵守。补码是为减法和负数而生的。如果你有兴趣也可以自己制定另一套负数和减法方案,把负数运算取为其他逻辑,但一定没有这种方案效率高。

一个简单的补码计算技巧是:要把一个负数用其补码写出来,首先把其对应的正数从右向左找到第一个1,这个1和以及它右边的那些0都不动,把这个1左边的全部数字取反,就得到对应的补码表示。

简单解释一下这种算法的原理:本质上讲,补码就是为负数而生的。计算机里没有负数的概念,所以把负数写成补码这种样子,通过最高位被进位实现正确的运算。

因为涉及最高位进位,所以尾部必然要多出来一个1用来实现相加进位。因此关键是从右向左找到最后一个1,最后一个1及之后的内容不变,之前内容全部取反。
示例:
-9的补码表示方法:
00001001 (+9)
从右向左找到最后一个1及之后的内容不变,之前内容全部取反:
11110111(-9)
同理,想看清补码形式的负数值,需要做逆变换:
从右向左找到最后一个1及之后的内容不变,之前内容全部取反:
00001001(+9)
-16的补码表示:
00010000(+16)
从右向左找到最后一个1及之后的内容不变,之前内容全部取反:
11110000(-16)
同理,想看清补码形式的负数值,需要做逆变换:
从右向左找到最后一个1及之后的内容不变,之前内容全部取反:
00010000(+16)

补码的发明,使CPU处理任何加减法运算都可以按加法进行,一步完成,不需要事先进行额外的符号位判断。所以在CPU的设计中只有ALU,而没有减法单元。

这就又涉及到一个有趣的现象,即补码运算的溢出。补码运算之所以会出现溢出,是因为表达位数受到限制:加超了,或者减超了。例如16位有符号数,可以表示的范围是+32767~-32768,那么如果让+32767再加上+32767,或者让-32768再减去+32767(也即(-32768)+(-32767)),结果肯定都是无法表示出来的,因为总数范围就在那里摆着呢。正常的减法操作是不会溢出的,从常识上即可判断,越减越少,不会出现“无法用言语表达”的尴尬。

通常的CPU设计中都有专门的溢出判断标志位(OF),不需要程序员去计算,只需读该状态位即可。但是原理还是要掌握的,CPU到底是靠什么判断计算溢出的呢?靠记录两个标志位:CS和CP。其中CS是符号进位记录,CP是向符号位进位的记录。还以16位数举例,如果两个正数补码相加,结果大于+32767,超出了表达范围,只能占据符号位,此时符号位被进位为1(发生了符号反转!),所以CP一定有进位,被置为1,而CS无进位,被置为0,结果CS:CP=0:1,发生了正溢出,CPU逻辑单元据此将OF=1,判断发生溢出。如果一个负数减去一个正数,就相当于两个负数相加,此时符号位相加肯定要发生进位,本身清为0,如果结果小于-32768,超出了表达范围,符号位不会被后面的数值相加进位(此为补码的数字逻辑原理,如果数值有进位发生就不会超出表达范围了,负数补码中符号位后面数字越大,表示的负数值越小,例如-1为0xFFFF,-32768为0x8000),所以CS一定会发生进位,被置为1,而CP一定无进位发生,被置为0,结果CS:CP=1:0,发生了负溢出,CPU逻辑单元据此将OF=1,判断发生溢出。

补码的发明,就是为了适应机器的运算模式,减轻机器的劳动强度。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值