Advertisement

那些年我们踩过的坑-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)

还没有任何评论哟~