本文主要谈谈计算机运算溢出问题 先来解一道简单的题目: 编写程序计算两个整数的和。相信学过任何一种编程语言的同学都可以轻松的写出代码来实现这个求和。 下面是C语言的代码实现: intsum(inta,intb){ } intmain(intargc,charargv〔〕){ if(argc3){ return1; } intaatoi(argv〔1〕); intbatoi(argv〔2〕); printf(ad,bd,sumd,a,b,sum(a,b)); return0; } 代码非常简洁,这份代码可以用gcc或者MSVC编译后执行。 下面是gcc编译运行后执行12的结果:。sum12 a1,b2,sum3 一切正常,我们再换一组数据试试:。sum21474836471a2147483647,b1,sum2147483648我们看到出问题了,a和b都是正数,结果sum却是负数。为什么会产生这种问题呢?实际上是计算产生了溢出,并且这种溢出计算机不会产生任何错误信号。 产生的原因是由于计算机表示数据的位数是有限的。在很多情况下,这种溢出是致命的,比如金融交易,科学运算等。所以我们有必要对其进行判断和处理。 我们知道int在32位和64位系统中都是4个字节表示的。解决上面溢出问题的一个最简单思考就是用更多的位数表示运算后的结果,比如用8个字节来表示求和后的结果。但有时候我们并不希望这样做,而希望能够判断计算是否产生溢出,从决定下一步操作。那该如何判断呢? 首先需要明确的是无符号数运算和有符号数运算的判断方法是不同的,下面逐一分析。 1。无符号数加法溢出判断: 对于无符号数相加如果产生溢出,则势必会向前产生进位,假设这个进位用z表示(z1表示有溢出,z0表示无溢出)。假设有两个n位的无符号数a,b相加(0a,b2n),那么为了保证其求和后结果不溢出,则至少需要n1位来存储运算结果。假设运算后的结果表示为M。而用n1位存储的运算结果为Q。 那么:Qz2nM。 显然,如果发生溢出(z1)则必有 0Mpdatatrack30所以对于Mab,如果未发生溢出则M2n,而发生溢出的判断条件为: M 2。有符号数加法溢出判断: 对于n位有符号数a,b(2(n1)a,b2(n1)1)求和,我们依然用M表示其运算后的结果。显然M的范围为〔2(n1),2(n1))。而ab表示的最大范围为〔2n,2n2〕。因此为保证其不溢出也需要n1来存储运算结果。 我们仍然用Q表示其n1的运算结果。那么可得: Q2(n1)(也就是Q大于等于M的上限),那么意味着ab产生了正向溢出。(1) QM(也就是2(n1)Q2(n1)),那么计算结果没有溢出。(2) Q2(n1)(也就是Q小于M的下限),那么计算结果产生了负向溢出。(3) 对于(1),一定有a0b0。而Q2nM。又因为(ab)的范围为〔2n,2n2〕,所以M必小于0。 对于(3),一定有a0b0。而Q2nM。又因为(ab)的范围为〔2n,2n2〕,所以M必大于0。 总结对于有符号数判断其是否溢出的条件为: 若a0b0并且(ab)0,则发生了正溢出。 若a0,则发生了负溢出。 有了上面的知识,我们再回过头看文章开始时的例子:a2147483647,b1,sum2147483648我们现在可以判断其发生了正向溢出,因为a为整数,b为整数,给定了a0b0,其计算结果sum0,所以产生了正向溢出。 如有兴趣大家也可以试试无符号数加法,看看能否根据文中提供的判据判断出无符号加法溢出的情况!