精度丢失问题
public static void main(String[] args) {
BigDecimal a = new BigDecimal(0.23);
BigDecimal b = new BigDecimal(0.33);
System.out.println(a.subtract(b));
}
结果:-0.1000000000000000055511151231257827021181583404541015625
原因
其实这个问题,在 BigDecimal(double) 的构造方法,注释上就有说明
这个构造函数的结果可能有些不可预测。 可以假设在Java中写入new BigDecimal(0.1)创建一个BigDecimal ,它完全等于0.1(非标尺值为1,比例为1),但实际上等于 0.1000000000000000055511151231257827021181583404541015625。 这是因为0.1不能像double (或者作为任何有限长度的二进制分数)精确地表示。 因此,正在被传递给构造的值不是正好等于0.1。
如何解决
- 通过BigDecimal(String)的构造参数
- 不使用构造参数,通过它的静态方法BigDecimal.valueOf(double)
注意事项
BigDecimal的equals方法很具有迷惑性,例如:1和1.0很多时候都会以为它的结果为true. 实则不然,BigDecimal的比较方法有个细节,在对比的时候是要比较scale的,也就是说如果scale不相等, 也是会返回false的。比如0和0.00,因为两者的scale是不同的,所以结果自然是false。 不得不说,确实从Decimal的设计原理上来说,确实这个考虑也是合理的,因此在使用的时候我们还是需要多多注意的。
解决方案
由于很多场景下我们都是在算费等场景下使用BigDecimal,所以在比对BigDecimal的时候,尽量使用compare方法(忽略scale)来比较,而非equals方法,可能更符合我们的需求。