1、为什么 double(或 float) 不精确?
- 计算机只认识二进制;
- 十进制小数转换成二进制,一般采用“乘二取整,顺序排列”的方法,但有的小数并不能转换成二进制,如 0.1 就不能直接用二进制表示。它的二进制是0.000110011001100……,这是一个无限循环小数;
- 为了解决不能转换成二进制的问题,人们想出了一种采用一定的精度,使用近似值表示一个小数的方法:IEEE 754(IEEE 二进制浮点数算数标准)规范的主要思想(IEEE 754 规定了多种表示浮点数值的方式,其中最常用的就是 32 位单精度浮点数 和 64 位双精度浮点数);
- 所谓精度不同,可以简单理解为保留有效位数不同。
2、BigDecimal 如何精确计数?
- 看源码就能发现:一个 BigDecimal 实际上是通过一个“无标度值”和一个“标度”来表示一个数的;
【scale】123.45:2
【unscaledValue】123.45:12345
【scale】-3000:0
【unscaledValue】-3000:-3000
* 标度通过 scale 字段来表示
* 无标度值的表示比较复杂
* 当 unscaled value 超过阈值(默认为 Long.MAX_VALUE)时采用 intVal 字段存储 unscaled value,intCompact 字段存储 Long.MIN_VALUE;
* 否则对 unscaled value 进行压缩存储到 long 型的 intCompact 字段用于后续计算,intVal 为空。
* 涉及到的字段如下:
public class BigDecimal extends Number implements Comparable<BigDecimal> {
private final BigInteger intVal;
private final int scale;
private final transient long intCompact;
}
- 标度到底是什么?
- 除了 scale 字段,还提供了 scale() 方法,用来返回这个 BigDecimal 的标度。
- 如果scale为零或正值,则该值表示这个数字小数点右侧的位数;
- 如果scale为负数,则该数字的真实值需要乘以10的 该负数的绝对值 的幂。例如,scale为-3,则这个数需要乘1000,即在末尾有3个0。
- eg:二进制无法表示的 0.1,使用 BigDeci