BigDecimal 使用总结

工作中很多情况下需要进行精确的小数运算,,在 Java 中使用 float 和 double 这两种浮点数类型进行小数运算时,往往很难达到令人满意的效果,小数点后面总是存在很多位的小数,看起来令人费解,因此不推荐使用这两种浮点数类型进行小数运算。BigDecimal 就是专门用来进行精确计算的,使用起来也非常方便,下面我们就通过代码一起看一下吧。


一、运算效果对比

先给出代码和运算结果,然后再进行结论总结。

package com.jobs;

import java.math.BigDecimal;

public class Demo1 {
    public static void main(String[] args) {

        double f1 = 0.1;
        double f2 = 0.2;
        double result1 = f1 + f2;
        System.out.println("Double相加的结果:" );
        System.out.println(result1);

        System.out.println("-----------------");

        //使用浮点数初始化BigDecimal
        BigDecimal bd1 = new BigDecimal(0.1);
        BigDecimal bd2 = new BigDecimal(0.2);
        BigDecimal result2 = bd1.add(bd2);
        System.out.println("浮点数初始化的BigDecimal相加的结果:");
        System.out.println(result2);

        System.out.println("-----------------");

        BigDecimal bd3 = new BigDecimal("0.1");
        BigDecimal bd4 = new BigDecimal("0.2");
        BigDecimal result3 = bd3.add(bd4);
        System.out.println("字符串初始化的BigDecimal相加的结果:");
        System.out.println(result3);

    }
}

执行的结果是:

image

从上面的执行结果,可以看出:

【double 类型的小数】和【使用浮点数初始化的 BigDecimal 】在进行小数运算后,结果并不是我们所期望的,甚至【使用浮点数初始化的 BigDecimal 小数】进行小数运算的结果,更加令人感到不爽。

【使用字符串初始化的 BigDecimal 】进行小数运算后的结果,是我们所期望的结果,因此后续尽量使用字符串来初始化 BigDecimal 。


二、BigDecimal 运算示例

还是先给出代码,再总结结论吧:

package com.jobs;

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

public class Demo2 {
    public static void main(String[] args) {

        BigDecimal bd1 = new BigDecimal("10");
        BigDecimal bd2 = new BigDecimal("3");

        //相加
        BigDecimal add = bd1.add(bd2);
        System.out.println("10/3 相加的结果:" + add);

        //相减
        BigDecimal subtract = bd1.subtract(bd2);
        System.out.println("10/3 相减的结果:" + subtract);

        //相乘
        BigDecimal multiply = bd1.multiply(bd2);
        System.out.println("10/3 相乘的结果:" + multiply);

        //相除(如果能够除尽,则一切正常)
        BigDecimal divide = bd2.divide(bd1);
        System.out.println("3/10 相除的结果:" + divide);

        //相除(如果除不尽,则抛异常)
        //原因:BigDecimal属于精确计算,如果除不尽,必须指定舍入规则
        BigDecimal divide0 = bd1.divide(bd2);
        System.out.println("10/3 相除的结果:" + divide0);
    }
}

执行的结果是:

image

从执行的结果,可以看出:

【使用字符串初始化的 BigDecimal 】在进行除法运算时,如果能够除尽的话,代码运行就正常,如果除不尽的话,就会抛出异常。原因就是 BigDecimal 属于精确运算,如果除不尽的话,必须要指定小数的舍入规则,这样才能确保运算的结果是我们预期的结果。


三、常用的小数舍入规则

系统提供了很多小数舍入规则,我们常用的也就是 3 种舍入规则:

  • RoundingMode.UP 进一法
  • RoundingMode.FLOOR 去尾法
  • RoundingMode.HALF_UP 四舍五入
package com.jobs;

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

public class Demo2 {
    public static void main(String[] args) {

        BigDecimal bd1 = new BigDecimal("10");
        BigDecimal bd2 = new BigDecimal("3");

        //常用的三个舍入规则为:
        //RoundingMode.UP 进一法
        //RoundingMode.FLOOR 去尾法
        //RoundingMode.HALF_UP 四舍五入

        System.out.println("相除精确2位小数:");

        BigDecimal divide1 = bd1.divide(bd2, 2, RoundingMode.UP);
        System.out.println("10/3 小数第3位进1的结果:" + divide1);

        BigDecimal divide2 = bd1.divide(bd2, 2, RoundingMode.FLOOR);
        System.out.println("10/3 小数第3位舍去的结果:" + divide2);

        BigDecimal divide3 = bd1.divide(bd2, 2, RoundingMode.HALF_UP);
        System.out.println("10/3 小数第3位四舍五入的结果:" + divide3);

        BigDecimal bd3 = new BigDecimal("0.1");
        BigDecimal bd4 = new BigDecimal("4");
        BigDecimal divide4 = bd3.divide(bd4, 2, RoundingMode.HALF_UP);
        System.out.println("0.1/4 实际结果是 0.025,小数第3位四舍五入的结果:" + divide4);
    }
}

执行结果如下:

image

以上就是三种舍入规则的效果演示,平时使用最多的应该还是四舍五入。我们在使用 BigDecimal 进行除法运算时,尽量指定要保留的小数位数,以及舍入规则,否则就会有除不尽导致代码执行过程中抛异常的风险。


Ok,到此为止,有关 BigDecimal 的基本使用,已经介绍的差不多了,相关的示例代码下载地址如下:

https://files.cnblogs.com/files/blogs/699532/BigDecimalDemo.zip


posted @ 2023-01-17 12:27  乔京飞  阅读(10773)  评论(0编辑  收藏  举报