通常我们在金融、科学等场景,会使用BigDecimal
。然而如果我们不注意BigDecimal
的精度问题,计算结果偏差可能会很大,最终会产生难以想象的Bug。
1意想不到的加减乘除
代码语言:javascript复制@Test
public void test3() {
BigDecimal param1 = new BigDecimal(0.1);
BigDecimal param2 = new BigDecimal(0.2);
//加法
BigDecimal add = param1.add(param2);
System.out.println("加法:" add);
//减法
BigDecimal subtract = param2.subtract(param1);
System.out.println("减法:" subtract);
//乘法
BigDecimal multiply = param1.multiply(param2);
System.out.println("乘法:" multiply);
//除法
BigDecimal divide = param2.divide(param1);
System.out.println("除法:" divide);
}
运行结果
程序的结果并不是我们想要的结果。这里实际是将数值做了二进制转换存在计算机中,取出时又转成了10进制,导致值产生了变化。
改进方法如下:
我们将
代码语言:javascript复制BigDecimal param1 = new BigDecimal(0.1);
BigDecimal param2 = new BigDecimal(0.2);
更改为
代码语言:javascript复制BigDecimal param1 = new BigDecimal("0.1");
BigDecimal param2 = new BigDecimal("0.2");
运行结果
所以我们在使用 BigDecimal
表示和计算浮点数时,一定要使用字符串的构造方法来初始化 BigDecimal
。
2除法运算记得保留小数点位数
代码语言:javascript复制@Test
public void test5() {
BigDecimal bParam = new BigDecimal("1");
BigDecimal bParam2 = new BigDecimal("3");
BigDecimal divide = bParam.divide(bParam2);
System.out.println(divide);
}
如上代码我们1除以3时结果会是无线循环小数,运行结果如下:
直接抛出异常了。为此,在使用BigDecimal
做除法运算时,我们记得保留小数点位数。
@Test
public void test5() {
BigDecimal bParam = new BigDecimal("1");
BigDecimal bParam2 = new BigDecimal("3");
BigDecimal divide = bParam.divide(bParam2, 3, BigDecimal.ROUND_HALF_EVEN);
System.out.println(divide);
}
运行结果为:
3烦人的小数点
如果你有一个Double
类型的数字,还有一个BigDecimal
类型的数字,现在我要对这两个数字做乘法:
Double dParam = 100d;
BigDecimal bParam = new BigDecimal("0.02");
BigDecimal toBigDecimal = new BigDecimal(dParam.toString());
BigDecimal multiply = bParam.multiply(toBigDecimal);
如上代码,我将Double
类型的100d
与BigDecimal
类型的0.02
相乘,我期望得到值为2.00
。我按照上面的方法做乘法后,得到的数为
小数点后面居然有3个0,想当然不是我想要的。
实际上我们只要做做小改动:
代码语言:javascript复制@Test
public void test4() {
Double dParam = 100d;
BigDecimal bParam = new BigDecimal("0.02");
BigDecimal toBigDecimal = new BigDecimal(dParam.toString());
BigDecimal multiply = bParam.multiply(toBigDecimal);
System.out.println(multiply.setScale(2, BigDecimal.ROUND_HALF_EVEN));
}
运算结果:
大部分业务需求会保留小数位数,我们可以在结果中设置小数位数即可。
4别用equals判断
我们在对包装类进行比较时,通常使用equals比较值,但是在BigDecimal
中使用equals
可能就不会得到我们想要的结果。
@Test
public void test6() {
System.out.println(new BigDecimal("1.0").equals(new BigDecimal("1")));
}
返回结果为:
扒开这里的equals
源码我们发现equals
比较的是BigDecimal
的value
和scale
,即比较了值和小数点位数。我们往往只需要比较值,那么这里可以使用compareTo
方法:
@Test
public void test6() {
System.out.println(new BigDecimal("1.0").compareTo(new BigDecimal("1")));
}
运行结果:
0代表的就是相等了。
这篇文章就写到这里了,如果对你有用,欢迎转发。