定点数的加减其实可以归为一类。
定点加减
定点加减运算主要用到补码运算。
加法表达式为[X+Y]补=[X]补+[Y]补;就是说X+Y补码的结果为X的补码加上Y的补码,即结果为补码。
减法表达式为[x-y]补=[X]补+[-Y]补;就是说X-Y的补码结果就是用加法表示的,是用X的补码和-Y的补码相加得到的。[-Y]补等于[Y]补各位取反,包括符号位,然后加1就得到了。
溢出
溢出就是给定一个固定的容器,容器里盛装的液体溢出来了,我就不多解释了。计算机中的溢出就是给了你一个固定的位数去盛放位数,某个数在这个容器里装不下了就是溢出。定点数的加减运算就会出现这种情况。
那么如何判断加减溢出,粗糙的方法是正正相加为负溢出,负负相加为正溢出,正-负为负溢出,负-正为正溢出。
高端操作判断溢出有个名字:变形补码法,其实特别简单,既可以看出溢出,也可以看出溢出的方向,是向正数方向溢出了还是负数方向溢出了,一目了然。
就是符号位用双符号位表示就可以啦,就这么简单。符号位为00、11为正负数,若出现01、10则溢出了。01为上溢,10为下溢了。
定点数的乘法运算
主要有原码一位乘、补码一位乘。
原码一位乘
符号位不参加运算,数值位均以绝对值出现,X*Y中X为被乘数,采用双符号位,Y为乘数,采用单符号位。部分积初始化为0。然后接下来的操作就是for循环了。
for(y的最低位;该位没有超出y最高位;y的下一位)
{ 若y该位为1,部分积+X的绝对值,生成的新的部分积右移一位;
若y该位为0,部分积+0,生成的新的部分积右移一位;
}
结果表示:X符与Y符的异或产生的符号作为结果的符号。
补码一位乘
符号位参与运算。
X*Y中,被乘数采用双符号位,乘数采用单符号位,乘数的最低位后添加上一个附加位,附加位值为0,仍然存在部分积。
for(y的最右边两位(初始的话为附加位与原来的最低位);y的两位不是小数点左右两边的数;y向左挪动两位)
{
若y的两位为00或11,则部分积+0,新的部分积右移两位;
若y的两位为01,则部分积+[X]补,新的部分积右移两位;
若y的两位为10,则部分积+[-X]补,新的部分积右移两位;
}
其实到这了现在,应该会发现原码一位乘与补码一位乘很相似,部分积都是要移动n次(即X、Y的最高有效位个数)。
定点数的除法运算
原码恢复余数法运算
符号位不参与运算,在X/Y中,X、Y的绝对值的补码需要。双符号位补码运算。
步骤:for(i=1;i<=X、Y的最高有效位个数;i++)
{
判断X>Y?
如果X>Y,商1,生成结果左移1位;
如果X<Y,商0,生成结果+Y绝对值补码,生成的结果左移1位;
}
结果为:商,余数,上述中最后生成的结果就是余数的尾数,余数由尾数与阶码表示,阶码一般为负数,左移几次就是几,例如:M*2的-5次方,就是余数产生左移了5次。
由于符号位不参加运算,最后商的符号为X、Y的符号异或产生,余数的符号与被除数的符号相同。
原码不恢复余数法运算
符号位不参加运算,参与运算的是绝对值的补码加减。整个过程类似一个循环的判断。假设余数最初为被除数。
判断:余数>除数,商1,结果左移1位,新生成的余数-除数;
余数<除数,商0,结果左移一位,新生的余数+除数;
该判断需要左移n次(即参与运算的数的有效位的个数)。若左移第n次产生的余数为负,需加上除数使余数为正。余数的符号与被除数的符号一致。
补码一位除
补码一位除设计到校正问题,此处只针对精度不严格的除法。
运算:补码双符号位的加减。
规则:被除数(余数)与除数同号,被除数(余数)-除数,若异号,被除数(余数)+除数;新生成的余数如果与除数同号,商1,结果左移一位;若新生成的余数如果与除数异号,商0,结果左移一位。如此往复,直到左移发生了n次(即被除数、除数的有效位个数)。
值得注意的是:最后一次上商,无论余数与除数是否同号,均商1。
到了现在,可以发现,原码的乘除没有符号位直接参与运算,因而都是对绝对值进行操作的。