强调:以下代码未溢出返回true 反之false
1.无符号加法
int uadd_ok(unsigned x, unsigned y)
{
unsigned sum = x+y;
return sum >= x;
}
/*解释:
由于x+y>=x,
若s没有溢出 则 s一定>=x;
若s未溢出 则 s = x+y-2^w 由x,y<2^w可得,y-2^w<0,因此s<x.
*/
2.补码加法
ps:下段代码在反写补码减法是否溢出时要注意y==Tmin时单独讨论。
int tadd_ok(int x, int y)
{
int sum = x+y;
int neg_over = x<0 && y<0 && sum>=0;
int pos_over = x>0 && y>0 && sum<=0;//此处sum可不等于0
return !neg_over && !pos_over;
}
/*解释:
有符号数据溢出分为正溢出和负溢出,对他们分别进行判断是相对容易的.
负溢出指的是两个负数相加超出数据类型最大表示范围而被截取为非负数(不可能截取为负数,但可能为0,理由是补码运算的本质为模运算,并且由于0的存在负数比正数多1位,所以负数理论最大相加可到达0处,而正数理论相加达不到0甚至不到-1)
反之同理
*/
需要注意的是,以下代码判断符号位溢出是错误的。
//!!!!!!!!!!!!!!!! ERROR CODE!!!!!!!!!!!!!!!!!
int tadd_ok(int x, int y)
{
int sum = x+y;
return (sum-x==y)&&(sum-y==x);
}
/*解释:
该结果恒为真,因为阿贝尔群的存在,补码加法运算满足结合律和交换律(无论溢出与否)
*/
3.乘法
写法1:
int tmult_ok(int x, int y)
{
int p = x*y;
// Either x is zero,or dividing p by x gives y
return !x || p/x == y;
}
/*解释:
理论证明稍麻烦,可见CSAPP书籍 P68-P69;
简要想法:
如果P没有溢出 则p/x == y;
反之溢出之后 则不相等。
x=0时由于不能做除数 已单独讨论
*/
写法2:
int tmult_ok(int x, int y)
{
int_64t p = (int_64t) x*y;//必须要写上强制类型转换(int_64t) x
// Either x is zero,or dividing p by x gives y
return p == (int)p ;
}
/*解释:
乘法运算溢出时,如果要保证绝对正确 字长增加,可通过与截取后的结果进行比对,以判定是否溢出。
*/