精度丢失 - js & java
一直以来,我们在交易系统中使用BigDecimal类做运算。这成为了一种习惯,导致我忘记了为什么用它。
原因:精度丢失
不管在 java 还是 js ,亦或者 python 中。
0.1 + 0.2 = 0.30000000000000004
所以,为了计算准确,我们使用BigDecimal
js中不存在原生的BigDecimal
Double
sign | exponent | fraction |
---|---|---|
1位 | 11位 | 52位 |
63 | 62-52(实际的指数大小-1024 ~ +1023) | 51-0 |
例:3.5
sign: 0
exponent: 10000000000
fraction: 1100000000000000000000000000000000000000000000000000
指数部分10000000000-1023=1
尾数部分11
根据规约形式尾数的整数部分为1
综上,得==1.11B * 10^+1^ = 11.1B = 21 + 20 + 2-1 [^二进制位表示 ] = 2^1^ + 2^0^ + 2^-1^ = 3.5==
3.5刚好可以用二进制表示,但是还有许多小数是无法用二进制表述的
例如:0.1
sign: 0
exponent: 01111111011
fraction: 1001100110011001100110011001100110011001100110011010
无法使用2x + 2y + …这样的形式表示
所以 0.1 + 0.2 == 0.3 false
BigDecimal
解决方案:不适用二进制,而是使用==十进制(BigInteger) + 小数点位置(scale)==来表示。
例如:100.001
unscaledValue:100001
scale:3
即,100.001 = 100001 * 10^-3^
运算操作
加法
x*10^-n^ + y*10^-m^ = x*10^-n^ + (y*10^-m+n^)*10^-n^ = (x + y*10^-m+n^) * 10^-n^ ,其中n > m
乘法
x*10^-n^ * y*10^-m^ = (x*y) * 10^n+m^
BigInteger
可以表示任意精度的整数,当你使用long类型进行运算的时候,可能产生长度溢出,此时就可以考虑使用BigInteger。BigDecimal就是使用它作为backend。
实现方案:==使用数组来存储==
参考资料