BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

点击上方蓝字关注我!



通常我们在金融、科学等场景,会使用BigDecimal。然而如果我们不注意BigDecimal的精度问题,计算结果偏差可能会很大,最终会产生难以想象的Bug。

1意想不到的加减乘除

@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);
}

运行结果

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

程序的结果并不是我们想要的结果。这里实际是将数值做了二进制转换存在计算机中,取出时又转成了10进制,导致值产生了变化。

改进方法如下:

我们将

BigDecimal param1 = new BigDecimal(0.1);
BigDecimal param2 = new BigDecimal(0.2);

更改为

BigDecimal param1 = new BigDecimal("0.1");
BigDecimal param2 = new BigDecimal("0.2");

运行结果

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

所以我们在使用 BigDecimal 表示和计算浮点数时,一定要使用字符串的构造方法来初始化 BigDecimal

2除法运算记得保留小数点位数

@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计算的这些坑,让我的程序产生难以想象的Bug

直接抛出异常了。为此,在使用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);
}

运行结果为:

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

3烦人的小数点

如果你有一个Double类型的数字,还有一个BigDecimal类型的数字,现在我要对这两个数字做乘法:

Double dParam = 100d;
BigDecimal bParam = new BigDecimal("0.02");
BigDecimal toBigDecimal = new BigDecimal(dParam.toString());
BigDecimal multiply = bParam.multiply(toBigDecimal);

如上代码,我将Double类型的100dBigDecimal类型的0.02相乘,我期望得到值为2.00。我按照上面的方法做乘法后,得到的数为

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

小数点后面居然有3个0,想当然不是我想要的。

实际上我们只要做做小改动:

@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));
}

运算结果:

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

大部分业务需求会保留小数位数,我们可以在结果中设置小数位数即可。

4别用equals判断

我们在对包装类进行比较时,通常使用equals比较值,但是在BigDecimal中使用equals可能就不会得到我们想要的结果。

@Test
public void test6() {
    System.out.println(new BigDecimal("1.0").equals(new BigDecimal("1")));
}

返回结果为:

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

扒开这里的equals源码我们发现equals比较的是BigDecimalvaluescale,即比较了值和小数点位数。我们往往只需要比较值,那么这里可以使用compareTo方法:

@Test
public void test6() {
    System.out.println(new BigDecimal("1.0").compareTo(new BigDecimal("1")));
}

运行结果:

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

0代表的就是相等了。

这篇文章就写到这里了,如果对你有用,欢迎转发。




往期推荐




BigDecimal计算的这些坑,让我的程序产生难以想象的Bug
BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

扫码二维码

获取更多精彩

Lvshen_9

BigDecimal计算的这些坑,让我的程序产生难以想象的Bug
BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

原文始发于微信公众号(Lvshen的技术小屋):BigDecimal计算的这些坑,让我的程序产生难以想象的Bug

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/262012.html

(0)
Java朝阳的头像Java朝阳

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!