java BigDecimal使用

一、BigDecimal的加减乘除:

package com.cy.test.math;

import java.math.BigDecimal;

public class TestBigDecimal {
    public static void main(String[] args) {
        //加法
        double d1 = 1.234;
        double d2 = 2.341;
        System.out.println(d1 + d2);    //3.575

        System.out.println(d1 * d2);    //2.8887940000000003精度出问题了
        System.out.println(d1 / d2);    //0.5271251601879539 这个是对的

        //使用BigDecimal,加法
        BigDecimal b1 = new BigDecimal(Double.toString(d1));
        BigDecimal b2 = new BigDecimal(Double.toString(d2));
        System.out.println(b1.add(b2).doubleValue());       //3.575

        //减法
        System.out.println(b1.subtract(b2).doubleValue());  //-1.107

        //乘法
        System.out.println(b1.multiply(b2).doubleValue());  //2.888794

        //除法  保留小数点后两位,四舍五入
        System.out.println(b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP)); //0.53
    }
}

 

二、BigDecimal转String的时候出现的精度问题:

有些两位类型的小数如double类型的,直接转化为String时,调用的是BigDecimal的toString方法,会出现精度问题。解决办法:

package com.cy.test.math;

import java.math.BigDecimal;

public class TestBigDecimal3 {

    public static void main(String[] args) {
        BigDecimal b1 = new BigDecimal(1.23);
        BigDecimal b2 = new BigDecimal(1.24);
        BigDecimal b3 = new BigDecimal(1.25);

        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b3);

        BigDecimal plus = b1.add(b2).add(b3);
        //直接打印会精度失真
        System.out.println(plus);
        System.out.println(String.valueOf(plus.floatValue()));

        //设置小数位数,第一个变量是小数位数,第二个变量是取舍方法(四舍五入)
        BigDecimal plus2 = b1.add(b2).add(b3).setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(plus2);
    }
}

打印结果:

1.229999999999999982236431605997495353221893310546875
1.2399999999999999911182158029987476766109466552734375
1.25
3.7199999999999999733546474089962430298328399658203125
3.72
3.72

 

三、BigDecimal的精度问题  

Because of floating point imprecision, you’re unlikely to get the value you expect from the BigDecimal(double) constructor.

例子:

package com.test.bigdecimal;

import java.math.BigDecimal;

public class TestBigDecimal {

    public static void main(String[] args) {
        Object object = 0.1;
        if (object instanceof Number) {
            BigDecimal result1 = new BigDecimal(((Number) object).doubleValue());
            System.out.println(result1.toString());

            BigDecimal result2 = BigDecimal.valueOf(((Number) object).doubleValue());
            System.out.println(result2.toString());
        }

    }
}

console:

0.1000000000000000055511151231257827021181583404541015625
0.1

结论:

1.new BigDecimal(double)可能会造成精度问题。应该使用BigDecimal.valueOf(double)方法。

 

四、RoundingMode

参考博客:https://zhuanlan.zhihu.com/p/445959759

BigDecimal.ROUND_DOWN:直接省略多余的小数,比如1.28如果保留1位小数,得到的就是1.2
BigDecimal.ROUND_UP:直接进位,比如1.21如果保留1位小数,得到的就是1.3
BigDecimal.ROUND_HALF_UP:四舍五入,2.35保留1位,变成2.4
BigDecimal.ROUND_HALF_DOWN:四舍五入,2.35保留1位,变成2.3
后边两种的区别就是如果保留的位数的后一位如果正好是5的时候,一个舍弃掉,一个进位。

ROUND_CEILING :向正无穷方向舍入
ROUND_FLOOR :向负无穷方向舍入
ROUND_HALF_EVEN :向(距离)最近的一边舍入,如果两边(的距离)是相等时,如果保留位数是奇数,使用ROUND_HALF_UP,如果是偶数,使用ROUND_HALF_DOWN
ROUND_UNNECESSARY :计算结果是精确的,不需要舍入模式

五、divide方法说明:

package com.test.bigdecimal;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class TestBigDecimal3 {
    public static void main(String[] args) {
        /**
         * divide()方法返回的精度是this.scale() - divisor.scale()
         * 如果除不尽就会报错
         * doc解释:
         * 返回一个BigDecimal,其值为(this / divisor),其首选标度为(this.scale() - divisor.scale());
         * 如果无法表示准确的商值(因为它有无穷的十进制扩展),则抛出ArithmeticException
         */
        BigDecimal dividend = new BigDecimal("100.00"); // 被除数
        BigDecimal divisor = new BigDecimal("3.00"); // 除数
        BigDecimal quotient = dividend.divide(divisor);
        System.out.println(quotient); // 报错

        /**
         * divide(BigDecimal divisor, int roundingMode),除法精度保存的是分子的scale,
         * 100.0只有1位精度,所以得到的结果是33.3
         */
        BigDecimal dividend1 = new BigDecimal("100.0"); // 被除数
        BigDecimal divisor1 = new BigDecimal("3.00"); // 除数
        BigDecimal quotient1 = dividend1.divide(divisor1, BigDecimal.ROUND_HALF_UP);
        System.out.println(quotient1); // 33.3

        /**
         * divide(BigDecimal divisor, int scale, int roundingMode),scale为给定精度
         */
        BigDecimal dividend2 = new BigDecimal("100.0"); // 被除数
        BigDecimal divisor2 = new BigDecimal("3.00"); // 除数
        BigDecimal quotient2 = dividend2.divide(divisor2, 2, BigDecimal.ROUND_HALF_UP);
        System.out.println(quotient2); // 33.33

        /**
         * setScale方法会改变原始BigDecimal对象的精度
         */
        BigDecimal dividend3 = new BigDecimal("100.0"); // 被除数
        BigDecimal divisor3 = new BigDecimal("3.00"); // 除数
        BigDecimal quotient3 = dividend3.divide(divisor3, 4, BigDecimal.ROUND_HALF_UP);
        System.out.println(quotient3); // 33.3333
        BigDecimal quotient4 = quotient3.setScale(3, RoundingMode.HALF_UP);
        System.out.println(quotient4); // 33.333
    }
}

 

六、multiply方法说明

package com.test.bigdecimal;


import java.math.BigDecimal;

public class TestBigDecimal2 {

    public static void main(String[] args) {
        /**
         * multiply(BigDecimal multiplicand)
         * javadoc解释:
         * 返回一个BigDecimal,其值为(this × multiplicand),其标度为(this.scale() + multiplicand.scale())。
         */
        BigDecimal t1 = new BigDecimal("100.0");
        BigDecimal t2 = new BigDecimal("0.1");
        BigDecimal t3 = new BigDecimal("0.5");

        BigDecimal r1 = t1.multiply(t2);
        BigDecimal r2 = r1.multiply(t3);
        System.out.println(r1);     //10.00
        System.out.println(r2);     //5.000
    }
}

 

 

---

posted on 2019-08-09 09:47  有点懒惰的大青年  阅读(1553)  评论(0)    收藏  举报