今天在自己做的系统中,发现了一个奇怪的现象:几个Double类型的数据相加,到最后得出的金额比正确数值总是少了几毛钱。以为是程序里的计算方法有问题,可是排查了很多地方,始终没有找到问题出在哪里。最后干脆把计算方法一句一句拆分,得到了最后最简单的一步,就是把两个具体的数值相加,但是最后的结果居然还是错误的。比如,现在已经到了最简单的一步:
代码如下:
double n = 171.6;
double m = 28.17;
double k = n + m;
按理说k的值应该是199.77,但其实得到的居然是199.76999999999998。
我们的系统里有保留小数位数为4位,按理是可以四舍五入成199.77的。但是因为有做金额的合计,是几十甚至几百个数据的相加,由于每两个数相加的时候都可能产生上述误差,因此最后得到的结果已经有了近0.7的误差,就算再四舍五入也于事无补了。
上网查了一下相关资料,觉得CSDN论坛里的这个帖子的解释还是比较详细的:http://bbs.csdn.net/topics/300023952,大意是说由于运算的时候进行了进制的转换造成的(见8楼回复),所有的精度类型在几乎所有语言下都有这个问题。比较有效的解决办法是使用BigDecimal(见14楼回复),但是我个人认为那个BigDecimal的解决办法太麻烦了,至少对于我的系统来说是这样。还不如每加一次之后都进行一次字符串转换,保留有效的小数位数,比如,上述语句可以改写成:
代码如下:
double n = 171.6;
double m = 28.17;
//double k = n + m;
String kn = (n + m).ToString("N4"); //保留4位小数
double k = Convert.ToDouble(kn);
也就是说,在String kn这一步,就已经把误差调整好了,得到的k值就是正确的了。这样每次相加都处理一下误差,无论要算多少个数据的合计也不用担心会出现误差过大的情况了。
当然最好是把这种处理方法做成一个公用方法,专门用来处理两个数的相加。