第一个坑:浮点类型的坑
先看看下面的代码的结果:
结果如下:
上面的a还是出现了精度的问题。
原因:是因为传入a之前,他已经是浮点型了--0.01;所以new BigDecimal时候就是会把它以近似值去保存下来。但是valueof不一样。这主要是它的源码设计:
在Valueof内部,会使用这个double.tostring方法去转换成字符串,所以就是不会存在精度问题。
第一个结论:
1、在使用BigDecimal构造函数中,尽量传递字符串而非浮点类型;
2、如果无法满足第一条,则可采用 BigDecimal.valueof去构造初始化值
第二个坑:浮点精度的坑
如果比较两个BigDecimal的值是否相等,你会怎么去比较呢?使用equals方法还是compareTo方法?
小tip:可以注意到这里使用了字符串的去构造函数
结果如下:
从结果上看是有区别的,compareTo是-1小于、0等于、1大于,显然equals不符合我们的期望。
这里我们需要去看看equals的源码:
这里其实能看出来除了去对比值是否相等,还能看出去对比了精度是否相同
当我们的程序会直接走到if(scale!=xDec.scale)就会去return false;这里是对比精度了,0.01和0.010是不同的。compareTo方法是实现了comparable接口,真正对比值大小。
第二个结论:
如果比较两个BigDecimal值的大小,采用compareTo方法;如果是严格限制精度的比较就是equals方法。
如果当我们要去比较0的时候,可以使用compareTo方法,比如BigDecimal("0"),BigDecimal("0.0")
第三个坑:设置精度的坑
这里我们进行计算的时候发现是无限小数,但是我们需要有限的就会报错。这时候我们需要去规划好它的精度,如:
这时候就是输出0.33,这里我还规定了“四舍五入”的方法--BigDecimal.ROUND_HALF_UP
一般我们就用这个,它一共是有8种:
RoundingMode.CEILING:取右边最近的整数
RoundingMode.DOWN:去掉小数部分取整,也就是正数取左边,负数取右边,相当于向原点靠近的方向取整
RoundingMode.FLOOR:取左边最近的正数
RoundingMode.HALF_DOWN:五舍六入,负数先取绝对值再五舍六入再负数
RoundingMode.HALF_UP:四舍五入,负数原理同上
RoundingMode.HALF_EVEN:这个比较绕,整数位若是奇数则四舍五入,若是偶数则五舍六入
第四个坑:三种字符串输出的坑
当我们使用BigDecimal需要去转换成string类型,如何去做呢?
这里明显我们的值不对,这里需要去知道三个方法:
toPlainString:不使用任何科学计数法;
tostring:在必要的时候使用科学计数法;
toEngineeringString:在必要的时候会使用工程计数法。基本上都是指数幂的3倍数。
第四个结论:根据数据结果不同展示的格式不同,采用不同的,比较多就是用toplainstring。
但是还是会舍去。这里是精度丢失。
这里小细节就是我们可以去设置后面的小数的位数去保证我们的精度: