关于C语言中的四舍五入,本来不是什么大问题,但是吃过亏后,就发现这么个小问题也能整得我痛苦不已。
在C98标准中,标准C函数库好像是没有关于四舍五入的函数的,到了C99标准才出现了ceil(),floor(),nearbyint(),round()之类丰富的取整函数。现在大家使用的gcc都是C99标准了,而Windows下的VC(包括VS2008)还是C98标准,所以你需要遵从严格的”三从四德“,包括没有内联inline,没有单行注释//,变量要写在代码块的前头,等等,最大的郁闷就是没有那些可爱的函数的支持。
针对C98,人家在处理四舍五入时,习惯上使用加0.5再取整的方法,但是这个方法是有极大缺陷的,或者说是很强的限制条件的。前些时为种子杯(一个校级的软件编程比赛)决赛搭框架时,就被这个方法害惨了。
现在有一个浮点型变量f,通过如下语句是否可以四舍五入呢?
int(f+0.5);
不行,问题在于它对负数不行,如果f=-1.9
,那么结果为-1,而不是想要的-2。你要注意对负数的取整相当于靠零取整,其效果与floor()函数在负数时,取整方向正好相反。再者对于负数来说,你需要做的是-0.5,而不是加0.5。当然对于负数的四舍五入,怎么定义的,不知道数学上有无定义过,这里就理解为四舍五入到最邻近的整数,也是非常合理的。因为我是要在一个长长的计算表达式里使用,当然就不想使用if判断,而且感觉问题如此简单,压根也没有想到会出那么多乱子。
各种曲折我也就不说了,直接摆上我的写法,当然尽管一改再改,一错再错,我硬是没有使用if判断。
float f = -2.9;
printf("%d\n",(int)(f+f-(int)(f)));
你可以发现,这里的技巧就是f-(int)(f)
如果为负数,那说明f是负数,其差值为负,其大小则决定了是四舍,还是五入,如果差值正好为-0.5,那正好是我们所需要的,所以便将差值加到f上,最后取整,得到结果。你仔细想想就会发现,如果f为正数,它应该也能工作得很好,我就不赘述了。
如此,我就纠结了一下午,怎么也不会想到是四舍五入出了问题。对于解决方法也想过,写个函数,使用if判断一把,但最终没有屈服。
如果你使用C99的编译器,你就不要跟自己过不去了,果断使用round()函数吧。