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

 

 

 

 

 

 

posted @ 2019-10-25 16:12  野猿新一  阅读(46)  评论(0编辑  收藏  举报