目前计算机中的数据普遍是用补码存储的,因为补码具有简单的加减法规则,运算简单,易于实现,而且符号位可以和数值位一起参与运算。
α. 补码规则运算
β. 溢出检测
γ. 机器数的移位运算
α 补码运算规则
补码的加减法运算公式为
在「Section 1」数据格式中我们有提过补码的减法是用加法来实现的,这里其实就是被减数的补码+减数相反数的补码,而一个正数相反数的补码显然为其各位(包括符号位)取反+1。
那么上述的公式又如何被证明呢?这里需要用数论中模(mod)的概念。我们知道正数的补码即为原码,而负数的补码则是各位取反+1,这两种情况是分开的,那是否有一种方式能将两者大一统呢?事实上,我们可以认为一个数的补码(算上符号位是 位的补码)是该数模 的结果: 这里的mod是取余的意思。我们规定余数必须为正,那么一个负数 模 的余数即为 ,就会发现补码的定义确实如此。
那么,
根据上式,第二个等式由 则显然成立。
β 溢出检测
我们很高兴地发现了补码运算的简便,但算着算着就会发现一些神奇的情况,比如说 怎么说呢,就是两个负数加起来变正了。想必,这就是物极必反吧(bushi
这个式子的真面目应该是 然而机器数的位数是有限制的,计算机难以容忍多出的一位,因此直接将最高位扔掉了,只是他不知道最高位有着特殊含义。这种现象我们称之为溢出(一般指上溢出)。
溢出在所难免,因此计算机必须解决溢出的问题,需要检测并指示。
❄︎ 单符号位判溢方法
我们清楚事实上只有当绝对值变大,即同号相加、异号相减(两者本质相同)的情况才会发生溢出,我们设 为溢出符号位, 为两个运算数的最高符号位, 为运算结果符号位,而 则表示运算符,0为+,1为-,那么有
❄︎ 进位判溢方法
❄︎ 双符号位判溢方法
当
γ 机器数的移位运算
- 逻辑移位:直接左右补0。将移位的数据视为无符号数据,各数据位在位置上发生了变化,导致无符号数据的数值(无正负)放大或缩小。(x86:SHL,SHR;RISC-V:sll,srl)
- 算术移位:将移位的数据视为带符号机器数。算术移位的结果,在数值的绝对值上进行放大或缩小,同时,符号位必须要保持不变。(x86:SAL,SAR;RISC-V:sll,sra)
- 补码的算数右移:高位补符号位
- 补码的算术左移:数据最高有效位必须与符号位相同才能保证不会溢出,此时可以直接将最高有效位移入符号位并在左边补0
- 循环移位:所有的数据位在自身范围内进行左移或者右移,左移时最高位移入最低位,右移时最低位移入最高位。(x86:ROL,ROR,RCL,RCR)