我们都知道如果要使用Java进行浮点数运算是不能直接使用+
,-
,*
,/
运算符去直接运算的,否则会丢失经度,类似这样的:
1 | double d = 0.1 + 0.2; |
输出的结果就是0.30000000000000004
,这个结果明显是有问题的。
要解决精度丢失的问题,一般我们会用到BigDecimal类,但是这个类其实也是有坑的。
- 坑1:如果使用构造方法创建BigDecimal,则参数必须为String类型的,否则还是会丢失精度,比如:
1 | BigDecimal bd2 = new BigDecimal("0.1"); |
运行的结果就是:
1 | 0.1 |
所以,如果要用构造方法去创建BigDecimal对象,则参数一定要是String类型的!
坑2:另一种创建BigDecimal对象的方法是使用BigDecimal类的valueOf()方法,问题是这个方法也有坑,如果你给的参数是long,double是没有问题的,如下:
1
2BigDecimal bd1 = BigDecimal.valueOf(0.1);
System.out.println(bd1);输出
0.1
,如果传给valueOf()一个float类型的参数会怎样呢?1
2BigDecimal bd2 = BigDecimal.valueOf(0.1f);
System.out.println(bd2);输出
0.10000000149011612
,发现问题了吧,出现了精度丢失的问题。关于为什么出现这个问题,可以看看valueOf()方法的源码1
2
3
4
5
6
7public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}底层是调用了构造方法,参数是用Double类的
toString()
方法把我们传进去的参数转换成了字符串,如果我们直接传递double类型的是没问题的,如果传递的是float类型的则会自动转换成double类型,类似1
2double d = 0.1f;
System.out.println(d);输出
0.10000000149011612
,看,丢失精度了吧。
所以,总结上面,如果使用BigDecimal类,则创建对象的时候如果使用构造方法,则参数一定要是String,就算不是,也要转换成String,如果使用valueOf()方法创建对象,则参数必须是long,double这种的。