BigDecimal源码阅读

258 阅读2分钟

笔者开发的系统属于财务类系统,金额计算特别多,而且都要求准确的精度,否则会出现对账失败。因此在系统中用BigDecimal特别多,虽然已经知道使用BigDecimal常见的坑,但是对于BigDecimal的原理还是不清楚,一直以为BigDecimal内部是使用字符串来存储数据,计算的时候使用类似我们平常列表达式计算的方式计算和进位。实际在阅读BigDecimal源码时才发现自己理解错了。

BigDecimal源码中,定义了4个最关键的要素:

public class BigDecimal extends Number implements Comparable<BigDecimal> {
   
    private final BigInteger intVal;
    private final int scale;  
    private transient int precision;
    private final transient long intCompact;
    ...
}

其核心思想为将小数转换为整数表示;例如: 123.12340 => 12312340*power(10,-5)=>对应为 intCompact:12312340,scale:5,precision:8; 其中scale表示的是变成整数需要放大的倍数,precision为变换为整数后整数的长度,这种表示跟数据库中的number(8,5)表示类似。最后一位0也保留了,这也是bigdecimal比较值相等要用compareTo,不能用equals的原因。

在转换的时候,如果值较小,则用long存值,放到intCompact中,如果值大,则放到BigInteger中;做了这样的处理后,后续进行计算则可以统一的模式进行处理;例如加减,先调整scale到相同,然后进行加减即可。如果是乘法就非常简单了,直接相乘,然后scale相加即可。除法比较复杂,后续再进行详细了解。在研究bigdecimal时,必然会看到BigInteger,BigInteger作为能处理理论上无穷大的数据,其实际也比较有意思,可以了解一下。