之前面试的时候被问到金额应该怎么存储,然后答的BigDecimal,然后因为真的没接触过,就没再多问什么,当初我也没多想就搁置了。然后昨天在看一个技术视频时候讲到金额存储,听完恍然大悟,今天来跟大家分享下。
之前就知道不能用float和和double存货币,但是不知道为什么不能存。那为什么不存呢?
1.为什么金额不能用float或double存呢?
首先,货币一般都会有小数,并且会有相应的计算。
先来看一个例子,猜猜如下代码打印的结果是什么?为什么?
。
。
。
。
不就是true 嘛!
。
你确认吗?
。
真正的结果是false。
来看结果
这是为什么呢?
怎么price3变成了0.29999998呢?稍安勿躁,且听我缓缓道来。
我们都知道,计算机在存取数字的时候是通过二进制01存储的。那咱们先来把0.7转成二进制。
首先我们知道整数部分转成二进制是对2求余,然后倒叙就转成了二进制,直到余数为零为止,然后倒序排列就好了,我就不举例了,大家可以自己试下。那小数应该怎么转成二进制呢?
正好相反,乘以2,首先把整数位置为0,然后对它进行乘2处理,然后取整数位的值,然后再把整数位置为0,再对它乘以2,再取整数位,直到小数位全部为0为止。
计算过程
0.7 *2 =1.4 得 1
0.4 *2 =0.8 得 0
0.8 *2 =1.6 得 1
0.6 *2 =1.2 得 1
0.2 *2 =0.4 得 0
。
。
。
发现没?第五行跟第二行一样了,产生了循环。所以0.7转换为二级制是0.101100110…它是无穷的。
因为计算机存储是有限位数,所以计算机并不能准确的表示0.7这个数字。
本来我也以为只有像π和三分之一那种无穷值不能存储的,没想到这个也不能存。其实也没有错,为啥呢?
因为0.7的二进制是无穷的。对于无穷的值,计算机也无能为力。
既然这种无穷数,float不能精确的存,那double也一样,只不过五十步笑百步罢了。只不过精度高低罢了。
2.那该怎么解决呢?
解决方案就是使用BigDecimal存储和运算,它可以精确的运算。
因为它存储时把小数转换(乘以10的次方)成整数存储。这样就不会有小数转换二进制的很有可能出现无穷值的破事了。
具体怎么操作呢?
首先获取货币的小数的总位数,然后直接乘以10的N次方转换成对应的长整型,再存储。
例如 存储17.1354元,直接乘以10000,存为171354,到运算的时候,直接用整型计算,需要显示的时候,再等比例缩小为原始精度即可。
来看下计算结果
那它有没有缺点呢?当然有了
1.首先复杂的数字计算起来不太方便;
因为bigDecmal计算的时候必须使用bigDecimal类内部的运算方法。所以复杂的运算还是不太方便的。
2.在调用bigDecimal的divide方法(即除法)时,要规定小数的保留位数。否则在除不尽的时候,会报错。
总结
今天总结下小数存储和计算的方案,当存金额的数据时,还是要多多考虑的。祝各位在未来的日子里,薪资翻倍,不掉头发。
❤️ 看完两件事
如果你觉得这篇内容对你有帮助,我想邀请你帮我个小忙:
- 关注我,并且点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)。
- 也看看我的其它文章。