那些年我们踩过的坑-BigDecimal精度丢失的问题
发布时间
阅读量:
阅读量
通常在Java中进行涉及小数点数字的计算时,建议采用BigDecimal类来处理。由于采用此方法通常能避免计算中的精度损失问题;然而,在操作不当的情况下,即使使用BigDecimal也可能导致精度丢失。试着猜测这段代码运行后会输出什么数值。
BigDecimal decimal = new BigDecimal(122.11);
System.out.println(decimal.toString());
//打印结果
122.1099999999999994315658113919198513031005859375
观察到结果不是122.11,在这种情况下 如果对decimal类型的数值进行计算处理 将会引发错误
希望避免进度信息丢失 可以将数值类型的数据转换为字符串形式 从而保证进度数据的完整性
BigDecimal decimal = new BigDecimal("122.11");
System.out.println(decimal.toString());
//正常结果
122.11
归因于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实现。该函数的作用是将双精度数值转换为对应的长整型数值。可以观察到该方法属于 native 类别,并其底层实现采用 C++ 语言编写。由此所得的长整型数值已不可避免地损失了精度。主要原因在于 double 类型无法精确表示所有具有有限二进制展开式的十进制数值。
public static native long doubleToRawLongBits(double value);
所以在初始化BigDecimal时推荐采用BigDecimal(字符串)
全部评论 (0)
还没有任何评论哟~
