当前位置:首 页 > 攻城湿 > 查看文章

判断算数运算溢出的方法

攻城湿 你是第1678个围观者 0条评论 供稿者: 标签:,

这是一个关于数据溢出的问题,如果你对这个知识点感兴趣请继续往下看。引入问题之前我们先温习一下溢出的概念:一个算数运算溢出,是指完整的整数结果不能放到数据类型的字长限制中去。

问题:写出一个具有如下原型的函数,如果参数x 和 y 相加不会产生溢出,这个函数就返回 1.

int tadd_ok(int x,int y);

错误的解决办法:

 /* WARNING: This code is buggy. */
 boolean tadd_ok(int x,int y){
     int sum=x+y;
     return (sum-x == y) && (sum-y == x);
 }

这段代码的思路是,如果发生了溢出 (x+y)-y 的结果就不会等于x,且 (x+y)-x 的结果也不会等于y.但实际测试结果是,函数 tadd_ok() 的返回值总是 true。为什么会产生这样的结果呢?下面先来看另一段代码:

public class demo01 {
    public static void main(String[] args) {
        int sum=2147483647+3;       //IntMax:2147483647
        System.out.println("sum="+sum);
        System.out.println("sum-3="+(sum-3));
    }

}
//output:
sum = -2147483646
sum-3 = 2147483647 

复制代码
  从上面代码中看到,2147483647+3 后发生了溢出,但是溢出后的值减3后又得到了原来的值2147483647。这看起来似乎不合常理,因为发生溢出后,超过数据类型字长限制的部分会被丢弃,这样运算的结果就不会是我们预期的值,而且逆运算之后也更加不会得到原来的初值,但实际情况却不是这样的。

  为了更直观地解释这种“诡异”的现象,我们假设机器字长为4位,x=9 和 x=12 的位表示分别为 [1001] 和 [1100],它们的和是21 (5位数字表示为 [10101]),但是机器位只有4位,于是最高位会被丢弃,我们就得到 [0101],也就是十进制的5.我们看到,在 x+y 的运算过程中发生了溢出,导致运算结果5与预期值21不符,但是模拟上面的程序,再进行逆运算会发生什么呢?即运算结果5减去9,如果5-9的结果等于12就说明与上面的程序运行结果相匹配,我们不妨仔细看看运算过程:

5-9 = 5 + (-9) = [0101] + [0111] = [1100] =12.

  上面的计算过程可能还不够清晰,’-9’的补码为什么是 [0111],[0111] 不是 7 的补码吗?难道说 -9 =7 吗?在这里给出两种解释方式:(这仅仅是我认为正确的思路,标准答案是什么还望高手不吝赐教)

    第一种解释:把 [0111] 并不是 ‘-9’ 的补码,而是表达式 (-9) 的4位二进制表示。我们知道,对于任意整数值 x ,计算表达式 -x 和 ~x+1 得到的结果完全一样。利用这个结论,我们可以得到 ‘-9’ 的位表示推理过程 [1001] 取反得到 [0110], 加1得 [0111].

    第二种解释:按照计算机中有符号数的存储规则, ‘-9’ 的补码按照不同位数表示是 [10111] 、[110111]、[1110111]…但是我们已经假设了机器字长为4位,所以必须丢弃超过限定字长的部分,丢弃后得到的补码就是 [0111].这与第一种解释相吻合。

  这样我们就能得出一个结论:即使加法产生了溢出,进行逆运算后的值依然等于参与运算的初值,即无论加法是否溢出,而(x+y)-y 总是会求值得到 x。

  好了,我们已经利用这个简单的例子说明这个运算时可逆的,也就证明了上面红体字部分的正确性,也就说明给出的解决办法是错误的。

正确的解决办法:

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;
     return !neg_over && !pos_over;
 }

  后记:数据的溢出往往会造成程序的不可靠性,所以在程序中应该考虑到这个问题所可能产生的后果,并采取必要的措施来处理这种情况。当然,这样做的前提是你已经对溢出有了比较深入的理解。

  

  注:本文整理自《深入理解计算机系统》.

【原文:http://www.cnblogs.com/wd-eco/p/3682009.html

这家伙很懒,什么都没写!

—— zhaorong

zhaorong
众说纷纭Comments
大眼 可爱 大笑 坏笑 害羞 发怒 折磨 快哭了 大哭 白眼 晕 流汗 困 腼腆 惊讶 憨笑 色 得意 骷髅 囧 睡觉 眨眼 亲亲 疑问 闭嘴 难过 淡定 抗议 鄙视 猪头
小提示:直接粘贴图片到输入框试试
努力发送中...
  • 评论最多
  • 最新评论
  • 随机文章
footer logo
未经许可请勿自行使用、转载、修改、复制、发行、出售、发表或以其它方式利用本网站之内容
Copyright © zhaorong All Rights Reserved. 滇ICP备15006105号-1