BigDecimal详解

 

 

参考博客:https://www.cnblogs.com/zhangyinhua/p/11545305.html (非常详细)

https://blog.csdn.net/haiyinshushe/article/details/82721234

 

一、BigDecimal概述

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。

BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

 

二、BigDecimal常用构造函数

常用构造函数

  1. BigDecimal(int)

    创建一个具有参数所指定整数值的对象

  2. BigDecimal(double)

    创建一个具有参数所指定双精度值的对象

  3. BigDecimal(long)

    创建一个具有参数所指定长整数值的对象

  4. BigDecimal(String)

    创建一个具有参数所指定以字符串表示的数值的对象

 

如:

        BigDecimal b1 = new BigDecimal(0.005);
        BigDecimal b2 = new BigDecimal(1000000);
        BigDecimal b3 = new BigDecimal(-1000000);
        //尽量用字符串的形式初始化
        BigDecimal bb1 = new BigDecimal("0.005");
        BigDecimal bb2 = new BigDecimal("1000000");
        BigDecimal bb3 = new BigDecimal("-1000000");    

 

BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。

 

三、BigDecimal的运算 (加、减、乘、除)

     //加法
        BigDecimal result1 = b1.add(b2);
        BigDecimal result12 = bb1.add(bb2);
        //减法
        BigDecimal result2 = b1.subtract(b2);
        BigDecimal result22 = bb1.subtract(bb2);
        //乘法
        BigDecimal result3 = b1.multiply(b2);
        BigDecimal result32 = bb1.multiply(bb2);
        //绝对值
        BigDecimal result4 = b3.abs();
        BigDecimal result42 = bb3.abs();
        //除法
        BigDecimal result5 = b2.divide(b1,20,BigDecimal.ROUND_HALF_UP);
        BigDecimal result52 = bb2.divide(bb1,20,BigDecimal.ROUND_HALF_UP);

 

3.1、除法divide()参数使用

使用除法函数在divide的时候要设置各种参数,要精确的小数位数和舍入模式,不然会出现报错。

## (BigDecimal divisor 除数, int scale 精确小数位,  int roundingMode 舍入模式)
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

 

四、BigDecimal常用方法详解

4.1、常用方法

  1. add(BigDecimal)

    BigDecimal对象中的值相加,返回BigDecimal对象

  2. subtract(BigDecimal)

    BigDecimal对象中的值相减,返回BigDecimal对象

  3. multiply(BigDecimal)

    BigDecimal对象中的值相乘,返回BigDecimal对象

  4. divide(BigDecimal)

    BigDecimal对象中的值相除,返回BigDecimal对象

  5. toString()

    将BigDecimal对象中的值转换成字符串

  6. doubleValue()

    将BigDecimal对象中的值转换成双精度数

  7. floatValue()

    将BigDecimal对象中的值转换成单精度数

  8. longValue()

    将BigDecimal对象中的值转换成长整数

  9. intValue()

    将BigDecimal对象中的值转换成整数

4.2、BigDecimal大小比较

java中对BigDecimal比较大小一般用的是bigdemical的compareTo方法

int a = bigdemical.compareTo(bigdemical2)

返回结果分析:

a = -1,表示bigdemical小于bigdemical2;
a = 0,表示bigdemical等于bigdemical2;
a = 1,表示bigdemical大于bigdemical2;

举例:a大于等于b

new bigdemica(a).compareTo(new bigdemical(b)) >= 0

 

测试

  public static void main(String[] args) {
        BigDecimal b1 = new BigDecimal(0.005);
        BigDecimal b2 = new BigDecimal(1000000);
        BigDecimal b3 = new BigDecimal(-1000000);
        //尽量用字符串的形式初始化
        BigDecimal bb1 = new BigDecimal("0.005");
        BigDecimal bb2 = new BigDecimal("1000000");
        BigDecimal bb3 = new BigDecimal("-1000000");
​
        //加法
        BigDecimal result1 = b1.add(b2);
        BigDecimal result12 = bb1.add(bb2);
        //减法
        BigDecimal result2 = b1.subtract(b2);
        BigDecimal result22 = bb1.subtract(bb2);
        //乘法
        BigDecimal result3 = b1.multiply(b2);
        BigDecimal result32 = bb1.multiply(bb2);
        //绝对值
        BigDecimal result4 = b3.abs();
        BigDecimal result42 = bb3.abs();
        //除法
        BigDecimal result5 = b2.divide(b1,20,BigDecimal.ROUND_HALF_UP);
        BigDecimal result52 = bb2.divide(bb1,20,BigDecimal.ROUND_HALF_UP);
​
        System.out.println("加法用number结果:"+result1);
        System.out.println("加法用string结果:"+result12);
​
        System.out.println("减法number结果:"+result2);
        System.out.println("减法用string结果:"+result22);
​
        System.out.println("乘法用number结果:"+result3);
        System.out.println("乘法用string结果:"+result32);
​
        System.out.println("绝对值用number结果:"+result4);
        System.out.println("绝对值用string结果:"+result42);
​
        System.out.println("除法用number结果:"+result5);
        System.out.println("除法用string结果:"+result52);
    }

 

BigDecimal详解

 

※ 注意:1)因为System.out.println()中的数字默认是double类型,double类型小数计算不精准。

2)使用BigDecimal类构造方法传入double类型时,计算的结果也不精确。

因为不是所有的浮点数都能够被精确的表示成一个double 类型值,有些浮点数值不能够被精确的表示成 double 类型值,因此它会被表示成与它最接近的 double 类型的值。必须改用传入String的构造方法

 

五、八种舍入模式

1、ROUND_UP 舍入远离零的舍入模式

在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。

注意,此舍入模式始终不会减少计算值的大小。

2、ROUND_DOWN 接近零的舍入模式

在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。

注意,此舍入模式始终不会增加计算值的大小。

3、ROUND_CEILING 接近正无穷大的舍入模式

如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;

如果为负,则舍入行为与 ROUND_DOWN 相同。

注意,此舍入模式始终不会减少计算值。

4、ROUND_FLOOR 接近负无穷大的舍入模式

如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;

如果为负,则舍入行为与 ROUND_UP 相同。

注意,此舍入模式始终不会增加计算值。

5、ROUND_HALF_UP 向上舍入的舍入模式(四舍五入)

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。

如果舍弃部分 >= 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。

6、ROUND_HALF_DOWN

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。

如果舍弃部分 > 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。

7、ROUND_HALF_EVEN

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。

如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;

如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。

注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。

此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。

如果前一位为奇数,则入位,否则舍去。

以下例子为保留小数点1位,那么这种舍入方式下的结果。

1.15>1.2 1.25>1.2

8、ROUND_UNNECESSARY

断言请求的操作具有精确的结果,因此不需要舍入。

如果对获得精确结果的操作指定此舍入模式,出现无限循环小数时,则抛出ArithmeticException。原文链接:https://blog.csdn.net/haiyinshushe/article/details/82721234

 

六、BigDecimal格式化

由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,可以利用BigDecimal对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。

以利用BigDecimal对货币和百分比格式化为例。首先,创建BigDecimal对象,进行BigDecimal的算术运算后,分别建立对货币和百分比格式化的引用,最后利用BigDecimal对象作为format()方法的参数,输出其格式化的货币值和百分比。

   @Test
    public void test(){
        NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用
        NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
        percent.setMaximumFractionDigits(3); //百分比小数点最多3位
​
        BigDecimal loanAmount = new BigDecimal("15000.48"); //贷款金额
        BigDecimal interestRate = new BigDecimal("0.008"); //利率
        BigDecimal interest = loanAmount.multiply(interestRate); //相乘
​
        System.out.println("贷款金额:\t" + currency.format(loanAmount));
        System.out.println("利率:\t" + percent.format(interestRate));
        System.out.println("利息:\t" + currency.format(interest));
​
    }

 

输出结果:

贷款金额:   ¥15,000.48
利率: 0.8%
利息: ¥120.00

 

总结

  1. 在需要精确的小数计算时再使用BigDecimal,BigDecimal的性能比double和float差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用BigDecimal。

  2. 尽量使用参数类型为String的构造函数。

  3. BigDecimal都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。

 

以上的知识点都是结合上面两个博客完成的。

上一篇:leetcode:二叉树的锯齿形层序遍历


下一篇:移动端 1px 像素处理