Bug 学习:一分钱的误差

前言:基本功相关错误,基本功扎实的同学不用浪费时间看了。

遇到一个有意思的bug,A系统的数据经过B系统后,发现个别数据少了一分钱。

A 系统数据单位是元,保留小数点后两位,而 B 系统单位是分。这里有个转化:

A 系统数字 * 100 得到分,赋值给 B 系统long型变量,示例代码如下,思考一下它会有什么问题?

1
2
3
4
5
double a = 0.28;
double b = 0.29;

System.out.println(a * 100);
System.out.println(b * 100);

答案是:





















1
2
28.000000000000004
28.999999999999996

接着如果再转long

1
2
3
4
5
double a = 0.28;
double b = 0.29;

System.out.println((long) (a * 100));
System.out.println((long) (b * 100));

输出是

1
2
28
28

单位是分,0.29元变成了28分,一分钱的误差产生了。

另外,类似例子

1
System.out.println(1f == 0.99999999f);

输出是 true

原因不再赘述,典型的精度问题,计算机基本功(我们看到的十进制数字在计算机中是以二进制表达的),但稍有不慎也很容易犯错。

看了下最终解决方案,也是典型的处理此类问题的通用方案,用大数类BigDecimal做运算,转long前先做下四舍五入。源码就不方便贴了,网上也到处都是。