在编写C/C++程序时应该小心使用四则运算法则,特别是交换率和结合率,这很容易产生不必要的溢出错误。
在C/C++中由于算术数据类型都存在上下限的问题,因此我们通常在四则运算中使用的运算法则在C/C++的算术运算中可能就是不成立的,但国内很多C/C++的书上经常会有“优化程序的一个方法就是通过四则运算法则来减少不必要的运算,从而提高程序的效率”,但它们很少提醒这样做所带来的安全隐患。
<script type="text/javascript">
</script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
在这些书上一个经典个的例子就是:
1*5+2*5+…+100*5
通过提取公因式
5*(1+2+3+…+100)
这样就减少了99个乘法操作,这当然提高了程序效率。但它们却没有提醒如果我们这里是取法,即:
2/2+4/2+6/2+…100/2
如果同样提取公因式
(2+4+6+…100)/2
这样就减少99次的除法,可同时也带来了很大的安全隐患——在求(2+4+6…+100)这个和的时候可能已经溢出了,这样得到的结果也就没有意义了。
举个更普遍的例子:
我们假设a,b是同一类型的数据,且其类型的上限为BOUND
a/2 + b/2 (1)
在一中为了使a/2 + b/2 <= BOUND,即不产生溢出,我们只要保证a/2 < BOUND/2 、b/2 < BOUND/2就OK了,也就是a, b<=BOUND,这是显而易见的也是完全可以满足的。
但如果我们使用四则运算法则,得到
(a + b )/2 (2)
问题就来了,为了保证程序的正确性,a + b <= BOUND 这样最后的结果(2)< BOUND/2,原式的运算结果范围被改变了,要求的条件也要变成a, b <=BOUND/2。这个小小的优化给我们带来了无穷的隐患。
在日常编程中,使用四则运算法则优化时一定要想好:自己的程序是否会在优化后的算式中产生溢出错误,如果会我们就只能忍痛割爱了。