3.1 定点数运算及溢出检测
一、定点数加法运算
[X]补+[Y]补=[X+Y]补mod2n+1
例如:
已知 X=+10010,Y=−10101, 求X+Y;
[X]补=010010,[Y]补=101011;
[X+Y]补=[X]补+[Y]补=010010+101011=111101
所以X+Y=−00011
二、定点数减法运算
[X−Y]补=[X]补−[Y]补=[X]补+[−Y]补
(由于最后一步装换,运算器的设计可以得到简化)
例如:
已知 [Y]补=10011,求[−Y]补
[Y]补=10011
所以Y=−1101,−Y=1101
所以[−Y]补=01101
对比[Y]补和[−Y]补可知:
通过右向左扫描[Y]补, 在遇到数字1及之前, 直接输出遇到的数字,
遇到1之后, 取反输出, 即可得到[−Y]补, 反之亦然!
又例如:
已知X=+10101,Y=+10010, 求X−Y
[X]补=010101,[Y]补=010010,[−Y]补=101110;
[X−Y]补=[X]补−[Y]补=010101+101110=1,000011 (首位的1溢出舍去)
所以:X−Y=+000011
三、数溢出的概念和判断方法
(1)概念:运算结果超出了某种数据类型的表示范围。
例如:X=+10010,Y=+10101,通过补码计算得到,X+Y=−11001
两个整数相加由于溢出得到了负数,不符合常识(同理还有两个负数相加得到正数)
(2)检测方法:
方法1:
对操作数和运算结果的符号位进行检测,当结果的符号位与操作数的符号不相同时就表明发生了溢出
V=X0Y0¯S0+¯X0Y0S0(设X0,Y0为参加运算数的符号位,S0为结果的符号位)
V=1时有溢出,反之没有;
该逻辑表达式的含义式:当两个操作数都是正数且结果是负数 或者 两个操作数是负数且结果是正数时V为1,反之为0。
根据逻辑表达式,可以很容易画出相应电路;
方法2:
对最高数据位进位和符号进位进行检测;
设运算时最高数据位产生的进位为C1, 符号位产生的进位为C0
则溢出检测电路为:V=C0⨁C1 (1表示溢出,0表示每溢出)
用理解的方式证明:
正数 + 负数肯定不会溢出,只用同号相加才有可能溢出;
假设是两个正数相加(除符号位部分我们分别设为X1,Y1)
0.X1
+ 0.Y1
----------
C0肯定为0,如果C1=1,则改变了符号位,发生了溢出;
假设是两个负数相加
1.X1
+ 1.Y1
----------
此时:C0=1, 若C1=0,则改变了结果符号位, 发生溢出;
方法3:用变型补码
[X]补=Xf1Xf2.X1X2X3…Xnmod2n+2
变型补码和普通补码相比有两个符号位,当数为非负数时,两个符号位为00,当数为负数时,两个符号位为11;
溢出的判断:V=Xf1⨁Xf2
例如: 已知X=−10010,Y=−10101,求X+Y
[X]补=11.01110,[Y]补=11.01011 (两位符号位,且都为11)
[X+Y]补=[X]补+[Y]补=1101110+1101011=1.1010001 (首位1溢出舍弃)
V=1⨁0=1, 因此出现溢出;
上述三种方法根据推导出的逻辑表达式很容易设计出硬件电路来检测;
方法4;溢出判断的软件方法
也可以通过代码来检测溢出:
bool check(int a, int b)
{
int sum = a + b;
if(a < 0 && b < 0 && sum >= 0) return true;
if(a > 0 && b > 0 && sum <= 0) return true;
}
似乎软件方法更简单,但软件方法会引起流水线的停顿,降低流水线的效率;
聚聚整理得真好!以后就得看你博客学习了
是凌乱之风巨巨,太荣幸了QwQ
好巧 刚给你点完就看见你几个小时以前给我点赞了 哈哈
哈哈这太巧了吧