问题描述及方案
- 假设我们在做电商项目,在进行计算时这个丢失精度在产品价格计算就会出现问题,很有可能造成我们手里有9.99元然后后面会有一堆9,但是呢这些钱无法购买一个10元的商品。
在某些编程语言中有专门处理货币的类型,但是Java没有,不过没关系我们可以通过BigDecimal
来解决这个问题。 - 下面我们来看几个例子。
testOne
- 这个呢就是Java本身对于浮点计算的时候会丢失精度,一定要注意,一定要注意,它所引起的事情呢基本没有小事,如果在线上订购量大的话,会引起大的故障,可能会导致下不了订单或是对账出现问题
testTwo
- 当使用BigDecimal后结果就更乱了,比test1结果还可怕又长又乱,它算出来的数比0.06是多的还是刚才那个意思,假设我们现在,
银行卡里面有0.06元然后我买的两个商品,分别是0.05元和0.01,当我下单的时候如果没有做处理那么他需要付的是0.06000000000000000298372437868010820238851010799407958984375 这就导致余额不够,订单无法下。这还没解决,不要紧,接着看
testThree
- 用String的BigDecimal构造器,这个结果就是我们想要的,本身呢BigDecimal这个类型是用它来解决这个问题但是我们在选择用它的时候,一定一定一定要选择它的String构造器一旦不用就像test2一样会发生严重过的精度问题,这个原则在《Effective Java》这本书中也有说,是说这个原则如果float和double只能用来做 科学计算或者工程计算,但是在商业计算中我们要用BigDecimal。
源码分析
1.说明
- 在java.math包中找到API类BigDecimal,然后找到BigDecimal(double)构造方法
- 源代码里写的很明白这个结果和这个构造器就会产生这个种问题它是无限接近于这么一个数这个构造器呢不是正好的,而是等于0.1
2.用法
- 如果用这个构造器呢,把它转成String,用Double的toString(double),里面放double然后用BigDecimal(String)这个String去构造,
也就是说如果要用的话,就把它转成String然后在选择用BigDecimal的String构造器去获得结果。另外3个这里就不讲了自己去看; - 为了方便我们可以把它写成一个util类,日后我整理完了会把它放在GitHub上。
原文:http://www.godql.com/blog/2017/05/17/Precision/
作者:Dr.Lester