[纸上谈兵]BigDecimal源码学习

一、BigDecimal声明
新来同事看到我们代码中BigDeciaml用法,感觉比较奇怪,由此引出了这篇文章

使用下面方式声明BigDecimal时,会出现精度问题
BigDecimal bd3 = new BigDecimal(0.1D);

推荐用法
BigDecimal bd1 = new BigDecimal("0.1");
BigDecimal bd2 = BigDecimal.valueOf(1D);

用以上方法就不会出问题精度问题
BigDecimal.valueOf() 查看源码就可以知道,也是使用的new BigDecimal("0.1")构造函数


注意:

BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。


二、为什么BigDecimal使用double或float会出现精度问题?

原因:十进制转二进制的算法导致转为二进制时,某些数字会永远不为零


十进制转二进制方法
整数部分:除以2,取出余数,商继续除以2,直到得到0为止,将取出的余数逆序
小数部分:乘以2,然后取出整数部分,将剩下的小数部分继续乘以2,然后再取整数部分,一直取到小数部分为零为止。如果永远不为零,则按要求保留足够位数的小数,最后一位做0舍1入。将取出的整数顺序排列

看了这个我想大家就都明白了,double或float之类的浮点数,转为二进制存储时某些数字会永远不为零

十进制转二进制例子:
整数部分: 我相信你会,你可以的。不会可以看我下面的参考资料
小数部分:乘以2,取整,小数部分继续乘以2,取整,得到小数部分0为止,将整数顺序排列
0.1x2=0.2 取整0,小数部分是2
0.2x2=0.4 取整0,小数部分是4
0.4x2=0.8 取整0,小数部分是8
0.8x2=1.6 取整1,小数部分是6
0.6x2=1.2 取整1,小数部分是2
。。。。。你会发出与前面重复了,会一直不停循环下去

三、为什么BigDecimal使用String不会出现精度问题
现在我们明白为什么用double,float 出现出精度问题。现在我们要看一下BigDecimal对String做了什么不会出现精度问题


首先: 程序就是数据结构与算法

通过Debug构造方法,我们可以了解,BigDecimal底层数据结构主要是由下面四个属性值组成.
int scale; //有多少位小数(即小数点后有多少位)
int precision; //总工有多少位数字
long intCompact; //字符串去掉小数点后,转为long的值,只有当传的字符串长度小于18时才使用该言
BigInteger intVal; //当传的字符串长度大于等于18时才使用BigInteger表示数字
以new BigDecimal("12.12")为例
scale值为2
precision值为4
intCompact值为1212

intVal值为空。之所以为空是因为字符串长度没有超18位,所以不启用BigInteger表示

看到这进而其实大家应该明白了,BigDecimal将String转为了long或BigInteger来进行计算。


四、使用Idea Debug BigDeciaml源码出现的奇怪现象
代码:
BigDecimal bd1 = new BigDecimal("1");
System.out.println("bd1:" + bd1);

上面的代码,不进行debug打印的结果是"bd1:1"
我们在Idea中同时在BigDeciaml类的411行打上断点(代码:if (offset + len > in.length || offset < 0) ,并非一定在这里打上断点,其实只要是在源码中加上断点能让这段代码走到debug即可,但不要在toString方法上加),然后debug运行,到了点断处,可以直接往下走,让代码执行完,你会发现结果是"bd1:0"。
原因是什么我还不明白,估计是idea的debug存在bug导致该问题产生  


五、TODO:

   加、减、乘、除,每个具体源码如何实现



参考:
https://blog.csdn.net/nesll/article/details/52302520
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值