一般java需要对有小数点数字进行计算的时候都是推荐使用BigDecimal因为用这个来计算不会出现精度丢失的问题 可是如果使用不当 BigDecimal其实也会有精度丢失的风险
下面的代码打印出来的结果可以猜猜是多少
BigDecimal decimal = new BigDecimal(122.11);
System.out.println(decimal.toString());
//打印结果
122.1099999999999994315658113919198513031005859375
可以看到结果不是122.11 这时候如果把decimal结果进行计算 是有问题的
想要进度不丢失 可以把122.11数字变成字符串
BigDecimal decimal = new BigDecimal("122.11");
System.out.println(decimal.toString());
//正常结果
122.11
之所以会这样 主要是因为BigDecimal字符串和双精度类型的构造函数里执行的代码不同
下面是BigDecimal双精度类型的构造代码
public BigDecimal(double val) {
long valBits = Double.doubleToLongBits(val);
}
public static long doubleToLongBits(double value) {
long result = doubleToRawLongBits(value);
if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
DoubleConsts.EXP_BIT_MASK) &&
(result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
result = 0x7ff8000000000000L;
return result;
}
上面的代码中核心是doubleToRawLongBits 通过双精度数字获取对应的long类型 可以看到这个方法是native方法 底层是c++实现的 通过这个获取的long类型已经精度丢失了 主要是因为double不能表示为任何有限长度的二进制小数
public static native long doubleToRawLongBits(double value);
所以在初始化BigDecimal时推荐采用BigDecimal(字符串)