精确计算,慎用float、double

783 阅读3分钟

这是我参与 8 月更文挑战的第 4 天,活动详情查看: 8月更文挑战

在我们日常的开发中,难免会遇到一些金额累加的计算,有些时候我们会用double,而在测试过程中会发现计算的结果并不是我们期望的结果;

首先说下float和double类型主要是为了科学计算而设计的,他们会通过二进制的方式来进行浮点运算,在通常情况下,他们的计算是没有问题的,而且可以快速的解决计算问题,但是在部分金融场景下,它无法满足我们想要的精确结果;

因为对于小数位,二进制无法精确表达十进制,(其他一些写法是float、double是不可能表达10的任何负数次方值)下面看例子:

double d1 = 0.11;
double d2 = 0.2;
System.out.println(d2-d1);

这个的结果是:0.09000000000000001;有没有发现,事情的结果并不尽如人意,它输出的是啥;有人看到后缀也许会问,尾数那么多,根本不需要那么精确,舍去即可,可是现实环境的数据是非常庞大且变化的,有各种运算,你如果全盘去后缀,免不了会丢掉价值数据的精确性吧,java也给我们提供了解决方案-->Bigdecimal

做过金融方面计算的同学肯定接触过这个类,如果没有,请自觉回去把这bug处理掉;当然了,有时候int、Long也可以解决部分问题但我觉得场景和应用方面存在局限性;

BigDecimal可以方便我们处理多种数据格式,加减乘除就不说了,处理小数位的setScale()方法可以按照你的想法来取多少位小数,以及取舍方式;还有方便的地方就是去除尾数0, stripTrailingZeros()可以去除尾数0。如果去除0后用 toString() 方法的话,有的数据会变为科学计数法,而 toPlainString() 则使用普遍计数法输出。

BigDecimal a=new BigDecimal("0.12300");
System.out.println(a.stripTrailingZeros().toPlainString());

结果是:0.123

既然BigDecimal这么简单,为什么平时还是不喜欢用它呢,而非得不得不用的时候才用,我们知道BigDecimal里的数字不会赋初始值,这里也乱入说个笔试题考点:

基本成员默认值的问题

这样会报错;

这样就不会报错,输出:0;所以一个变量的作用域在整个类的范围,不需要手动给它赋初始值,JVM会自动赋等类型的值,

对于非基本类型,类变量会输出null,所以平时我们得初始化,而局部变量我们还得首先赋初始值,不然编译都过不去;

好了,再回头说BigDecimal,相对于基本运算来说,BigDecimal操作繁琐,而且因为创建对象,所谓速度上也稍慢,当然,速度不够,机器来凑;

最后总结:如果你觉得你对数据的精确度要求不是很高,且想方便计算,那基本数据运算就可以了,没必要到处new BigDecimal();如果你对数据有严格要求,且想对数据做一些处理的话,那BigDecimal的方法应该可以帮你省去很多烦心事;