java double精度丢失引发的血案
公司做的无人便利店用的微信支付,微信支付传的支付值是以分为单位的,而公司的商品是以元为单位的,所以计算出来的价格还要乘以100,其中有一个可乐的商品定价是2.3元,但是乘以100后结果却是229.99999999999997,直接舍弃小数点后的值后为229,而不是230,比实际需支付的少了了一分钱,这一分钱到底那去了呢?
公司财务找上门来了,虽然是一分钱,那也是钱啊。
double yuan = 2.3;
double fen = yuan*100;
int price = (int) fen;
System.out.println(price); // 结果为229
这是因为double在乘的操作中精度丢失了,对于有关金钱的商业操作,不建议用基本数据类型double进行运算操作,要用BigDecimal
方法一:四舍五入
在上面的操作中,我们在把2.3*100的结果double值转成int的时候采用的是强制类型转换,这种方法直接把小数点后的值直接舍弃了,若采用四舍五入还是可以得到我们想要的结果的
System.out.println(Math.round(2.3*100)); // 结果为230
System.out.println(new BigDecimal(2.3*100).setScale(0, BigDecimal.ROUND_HALF_UP)); // 结果为230
方法二:BigDecimal(推荐)
对于数据结果精度要求比较高的,我们都推荐用BigDecimal来操作,先把操作数转成BigDecimal再进行加减乘除的操作
我们先封装一个BigDecimal的加减乘除工具类
import java.math.BigDecimal;
public class BigDecimalUtil {
public static double sum(double d1, double d2) {
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
return bd1.add(bd2).doubleValue();
}
public static double sub(double d1, double d2) {
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
return bd1.subtract(bd2).doubleValue();
}
public static double mul(double d1, double d2) {
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
return bd1.multiply(bd2).doubleValue();
}
public static double div(double d1, double d2, int scale) {
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
return bd1.divide(bd2).doubleValue();
}
}
然后重新上面的计算,就不会精度丢失了
double result = BigDecimalUtil.mul(2.3, 100);
System.out.println(result); // 结果为230.0