浮点类型数值的精度问题产生的原因:
- 首先,任何数据在内存中都是以二进制的形式存储的(0和1)
- 浮点类型数值存储在内存前,也需要将十进制的数据转换为二进制(底层实现)
- 然而,由十进制数值转换成二进制数值也是有一定的条件
- 1)任意十进制的整数都可以转换成有限位数的二进制整数(分解为2^n组合,其中 n >= 0)
- 如 171 (2^0 + 2^1 + 2^3 + 2^5 + 2^7) 转换为二进制整数10101011
- 2)十进制的小数能够分解为 (1/2)^n 时,才能转换成有限位数的二进制小数
- 如 0.9375 (1/2 + 1/4 + 1/8 + 1/ 16) 就能够转换成二进制小数:0.1111
- 1)任意十进制的整数都可以转换成有限位数的二进制整数(分解为2^n组合,其中 n >= 0)
- 因此,当无法满足转换规则,出现无限分解的情况时,就需要采用截断的形式
- 如 0.1 (1/16 + 1/32 + 1/256 + 1/512 + …) 无法完全分解为(1/2)^n时,会无限循环下去,不断地逼近 0.1 这个数值
-
BigDecimal类的解决方式
将原来的浮点类型数值,扩大10^n,以整数的形式进行计算操作(BigInteger)
- 并记录小数点位置(scale)
- 注意:scale的值是根据两个待计算值的小数点决定的
- 计算完成后,根据小数点的位置,再除以10^n,得到计算结果
BigDecimal num1 = new BigDecimal("101.101");
// num.scale() 的值为3,表示有三个小数
// num.unscaledValue() 的值为101101,将原来十进制数值扩大了10^3
BigDecimal num2 = new BigDecimal("201.12");
BigDecimal result = num1.add(num2); // 结果为302.221
BigDecimal result2 = num1.multiply(num2); // 结果为20333.43312