BigDecimal加减乘除

 

目录

 

三、BigDecimal的加、减、乘、除、绝对值

1、加法

       加法对应的方法有两个:

(1)public BigDecimal add(BigDecimal augend);

       方法返回的是一个BigDecimal对象,值为当前对象的值加上被加数对象augend的值(this+augend)。保留的小数位数是max(this.scale(), augend.scale()).

(2) public BigDecimal add(BigDecimal augend,MathContext mc);

       方法返回的是一个BigDecimal对象,值为当前对象的值加上被加数对象augend的值(this+augend),并根据上下文设置进行舍入。(关于上下文MathContext,前文已解释过)

       加法示例如下,


   
   
  1. @Test
  2. public void testAdd () {
  3. //用double类型初始化BigDecimal对象
  4. BigDecimal numA = new BigDecimal( 0.05);
  5. BigDecimal numB = new BigDecimal( 0.06);
  6. System.out.println( "numA + numB = " + numA.add(numB));
  7. //用double类型和int类型初始化BigDecimal对象。(作加法运算时得到的只是一个近似值)
  8. BigDecimal numC = new BigDecimal( 3.05);
  9. BigDecimal numD = new BigDecimal( 100);
  10. System.out.println( "numC + numD = " + numC.add(numD));
  11. //用字符串类型初始化BigDecimal对象。(作加法运算时得到的是精确值)
  12. BigDecimal strA = new BigDecimal( "3.05");
  13. BigDecimal strB = new BigDecimal( "100");
  14. System.out.println( "strA + strB = " + strA.add(strB));
  15. }

      打印的结果如下:

numA + numB = 0.11000000000000000055511151231257827021181583404541015625
numC + numD = 103.04999999999999982236431605997495353221893310546875
strA + strB = 103.05

       可以看到,使用double类型初始化BigDecimal 对象,进行加法运算时就出现了精度问题。正如前文所说,并不是所有的浮点数都能够在二进制系统中被精确的表示,自然而然的在进行加减乘除运算时就会出错。

2、减法

       对应的方法有两个:
(1)public BigDecimal subtract(BigDecimal subtrahend);

       方法返回的是一个BigDecimal对象,值为当前对象的值减去被减数对象subtrahend的值(this-subtrahend)。保留的小数位数是max(this.scale(), subtrahend.scale()).。   

(2)public BigDecimal subtract(BigDecimal subtrahend,MathContext mc);

       方法返回的是一个BigDecimal对象,值为当前对象的值减去被减数对象subtrahend的值(this-subtrahend),并根据上下文设置进行舍入。

       减法示例如下,


   
   
  1. @Test
  2. public void testSubtract () {
  3. //用double类型初始化BigDecimal对象
  4. BigDecimal numA = new BigDecimal( 0.05);
  5. BigDecimal numB = new BigDecimal( 0.06);
  6. System.out.println( "numA + numB = " + numA.subtract(numB));
  7. //用double类型和int类型初始化BigDecimal对象。(作减法运算时得到的只是一个近似值)
  8. BigDecimal numC = new BigDecimal( 100);
  9. BigDecimal numD = new BigDecimal( 0.05);
  10. System.out.println( "numC + numD = " + numC.subtract(numD));
  11. //用字符串类型初始化BigDecimal对象。(作减法运算时得到的是精确值)
  12. BigDecimal strA = new BigDecimal( "100");
  13. BigDecimal strB = new BigDecimal( "0.05");
  14. System.out.println( "strA + strB = " + strA.subtract(strB));
  15. }

       打印结果如下:

numA + numB = -0.00999999999999999500399638918679556809365749359130859375
numC + numD = 99.94999999999999999722444243843710864894092082977294921875
strA + strB = 99.95

3、乘法

       对应的方法有:

(1)public BigDecimal multiply(BigDecimal multiplicand);

       方法返回的是一个BigDecimal对象,值为当前对象的值乘于被乘数对象multiplicand的值(this*multiplicand)。保留的小数位数是(this.scale() + multiplicand.scale()).。   

(2)public BigDecimal multiply(BigDecimal multiplicand,MathContext mc);

      方法返回的是一个BigDecimal对象,值为当前对象的值乘于被乘数对象subtrahend的值(this*multiplicand),并根据上下文设置进行舍入。

      乘法示例如下,


   
   
  1. @Test
  2. public void testMultiply () {
  3. //用double类型初始化BigDecimal对象
  4. BigDecimal numA = new BigDecimal( 0.05);
  5. BigDecimal numB = new BigDecimal( 0.06);
  6. System.out.println( "numA + numB = " + numA.multiply(numB));
  7. //用double类型和int类型初始化BigDecimal对象。(作乘法运算时得到的只是一个近似值)
  8. BigDecimal numC = new BigDecimal( 100);
  9. BigDecimal numD = new BigDecimal( 0.05);
  10. System.out.println( "numC + numD = " + numC.multiply(numD));
  11. //用字符串类型初始化BigDecimal对象。(作乘法运算时得到的是精确值)
  12. BigDecimal strA = new BigDecimal( "100");
  13. BigDecimal strB = new BigDecimal( "0.05");
  14. System.out.println( "strA + strB = " + strA.multiply(strB));
  15. }

       打印结果如下,


   
   
  1. numA + numB = 0.00300000000000000005551115123125782085820576136538628584587058372823258067807472571075777523219585418701171875
  2. numC + numD = 5.00000000000000027755575615628913510590791702270507812500
  3. strA + strB = 5.00

 

4、除法

       对应的方法主要有:

(1) public BigDecimal divide(BigDecimal divisor);

       返回一个BigDecimal,其值为(this/divisor),首选小数位数为(this.scale()-divisor.scale());如果无法表示精确的商(因为它具有非终止的十进制扩展),则会引发算术异常。

(2) public BigDecimal divide(BigDecimal divisor,MathContext mc);

       返回值为(this/divisor)的BigDecimal,并根据上下文设置进行舍入。

 (3) public BigDecimal divide(BigDecimal divisor,int scale,int roundingMode);

       返回一个BigDecimal,其值为(this/divisor),其小数位数与指定的相同。如果必须执行舍入才能生成具有指定比例的结果,则应该用指定的舍入模式。

(4) public BigDecimal divide(BigDecimal divisor,int scale,RoundingMode roundingMode);

       返回一个BigDecimal,其值为(this/divisor),其小数位数与指定的相同(由第二个参数scale指定)。如果必须执行舍入才能生成具有指定比例的结果,则应该用指定的舍入模式(由第三个参数roundingMode指定)。

       (3)(4)两个方法其实是一样的,区别只在于第三个参数的指定方式。第一个方法是int roundingMode,即传入的是一个整型数字,而第二个方法是RoundingMode roundingMode,即传入的是一个RoundingMode对象。

       这里需要对RoundingMode作一下介绍。

     RoundingMode

       RoundingMode是一个枚举类,内部有8个枚举常量,分别是:

       UP:远离0的舍入模式,在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。放到一维坐标轴上就很容易理解,就是以0为分隔点,0右侧部分一直向右舍入,0左侧部分一直向左侧舍入。例如0.333保留两位小数,采用UP舍入模式的结果为0.34,-0.333保留两位小数,采用UP舍入模式的结果为-0.34。

       DOWN:和UP相反,是接近零的舍入模式。理解了UP舍入模式,就很容易理解DOWN舍入模式。例如0.333保留两位小数,采用DOWN舍入模式的结果为0.33,-0.333保留两位小数,采用DOWN舍入模式的结果为-0.33。可以发现,在采用DOWN模式进行舍入的时候,直接把需要舍弃的位数丢掉就行了。

       CEILING:CEILING英文是天花板的意思,可以理解为向”大“舍入。如果 BigDecimal 为正,则舍入行为与 UP 相同,如果为负,则舍入行为与 DOWN 相同。例如0.333保留两位小数,采用CEILING舍入模式的结果为0.34(0.34 >0.333),-0.333保留两位小数,采用CEILING舍入模式的结果为-0.33(-0.33>0.333 )。

       FLOOR:与CEILING相反,FLOOR有地板的意思,可以理解为向”小“舍入。如果 BigDecimal 为正,则舍入行为与 DOWN 相同,如果为负,则舍入行为与 UP 相同。例如0.333保留两位小数,采用FLOOR舍入模式的结果为0.33,-0.333保留两位小数,采用FLOOR舍入模式的结果为-0.34。

       HALF_UP:向”最接近的“数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 >= 0.5,则舍入行为与 UP 相同,否则舍入行为与 DOWN 相同。其实就是四舍五入。

       HALF_DOWN:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 > 0.5,则舍入行为与UP 相同,否则舍入行为与 DOWN 相同。与四舍五入的思路是一样的,只不过这里是”五舍六入“。如果扣字面意思的话,也很好理解,HALF_UP,half是一半的意思,也就是5,UP是向上的意思,就可以理解为5向上入,即四舍五入。同理,HALF_DOWN,5向下舍,即五舍六入。

       HALF_EVEN:向“最接近的”数字舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 UP 相同,如果为偶数,则舍入行为与 DOWN 相同。如0.135,保留两位小数,舍弃5,因为3是奇数,所以与UP相同,结果为0.14;0.125,保留两位小数,舍弃5,因为2是偶数,所以与DOWN相同,结果为0.12.

       UNNECESSARY:以断言请求的操作具有精确的结果,因此不需要舍入。如果有舍入,会报java.lang.ArithmeticException异常。

       关于这几个舍入模式的结果,亦可参照下面的表进行快速学习。

保留整数,不同舍入模式下的计算结果
原数UPDOWNCEILINGFLOORHALF_UPHALF_DOWNHALF_EVENUNNECESSARY
5.56565656throw ArithmeticException
2.53232322throw ArithmeticException
1.62121222throw ArithmeticException
1.12121111throw ArithmeticException
1.011111111
-1.0-1-1-1-1-1-1-1-1
-1.1-2-1-1-2-1-1-1throw ArithmeticException
-1.6-2-1-1-2-2-2-2throw ArithmeticException
-2.5-3-2-2-3-3-2-2throw ArithmeticException
-5.5-6-5-5-6-6-5-6throw ArithmeticException
         

       代码示例如下,


   
   
  1. @Test
  2. public void testDivide () {
  3. BigDecimal numA = new BigDecimal( "1");
  4. BigDecimal numB = new BigDecimal( "-1");
  5. BigDecimal numC = new BigDecimal( "3");
  6. // 保留两位小数,舍入模式为UP
  7. System.out.println( "1/3保留两位小数(UP) = " + numA.divide(numC, 2, RoundingMode.UP));
  8. System.out.println( "-1/3保留两位小数(UP) = " + numB.divide(numC, 2, RoundingMode.UP));
  9. // 保留两位小数,舍入模式为DOWN
  10. System.out.println( "1/3保留两位小数(DOWN) = " + numA.divide(numC, 2, RoundingMode.DOWN));
  11. System.out.println( "-1/3保留两位小数(DOWN) = " + numB.divide(numC, 2, RoundingMode.DOWN));
  12. // 保留两位小数,舍入模式为CEILING
  13. System.out.println( "1/3保留两位小数(CEILING) = " + numA.divide(numC, 2, RoundingMode.CEILING));
  14. System.out.println( "-1/3保留两位小数(CEILING) = " + numB.divide(numC, 2, RoundingMode.CEILING));
  15. // 保留两位小数,舍入模式为FLOOR
  16. System.out.println( "1/3保留两位小数(FLOOR) = " + numA.divide(numC, 2, RoundingMode.FLOOR));
  17. System.out.println( "-1/3保留两位小数(FLOOR) = " + numB.divide(numC, 2, RoundingMode.FLOOR));
  18. BigDecimal numD = new BigDecimal( "1");
  19. BigDecimal numE = new BigDecimal( "-1");
  20. BigDecimal numF = new BigDecimal( "8");
  21. // 保留两位小数,舍入模式为HALF_UP
  22. System.out.println( "1/8(=0.125)保留两位小数(HALF_UP) = " + numD.divide(numF, 2, RoundingMode.HALF_UP));
  23. System.out.println( "-1/8(=0.125)保留两位小数(HALF_UP) = " + numE.divide(numF, 2, RoundingMode.HALF_UP));
  24. // 保留两位小数,舍入模式为HALF_DOWN
  25. System.out.println( "1/8(=0.125)保留两位小数(HALF_DOWN) = " + numD.divide(numF, 2, RoundingMode.HALF_DOWN));
  26. System.out.println( "-1/8(=0.125)保留两位小数(HALF_DOWN) = " + numE.divide(numF, 2, RoundingMode.HALF_DOWN));
  27. // 保留两位小数,舍入模式为HALF_EVEN
  28. System.out.println( "0.54/4(=0.135)保留两位小数(HALF_EVEN) = " + new BigDecimal( "0.54").divide( new BigDecimal( "4"), 2, RoundingMode.HALF_EVEN));
  29. System.out.println( "1/8(=0.125)保留两位小数(HALF_EVEN) = " + numE.divide(numF, 2, RoundingMode.HALF_EVEN));
  30. //UNNECESSARY,会报异常
  31. System.out.println( "1/8(=0.125) = " + numE.divide(numF, RoundingMode.UNNECESSARY));
  32. }

打印结果:

1/3保留两位小数(UP) = 0.34
-1/3保留两位小数(UP) = -0.34
1/3保留两位小数(DOWN) = 0.33
-1/3保留两位小数(DOWN) = -0.33
1/3保留两位小数(CEILING) = 0.34
-1/3保留两位小数(CEILING) = -0.33
1/3保留两位小数(FLOOR) = 0.33
-1/3保留两位小数(FLOOR) = -0.34
1/8(=0.125)保留两位小数(HALF_UP) = 0.13
-1/8(=0.125)保留两位小数(HALF_UP) = -0.13
1/8(=0.125)保留两位小数(HALF_DOWN) = 0.12
-1/8(=0.125)保留两位小数(HALF_DOWN) = -0.12
0.54/4(=0.135)保留两位小数(HALF_EVEN) = 0.14
1/8(=0.125)保留两位小数(HALF_EVEN) = -0.12

java.lang.ArithmeticException: Rounding necessary

5、绝对值

   public BigDecimal abs();
   
   

       返回一个BigDecimal,其值为该BigDecimal的绝对值,其小数位数为this.scale()。

   public BigDecimal abs(MathContext mc);
   
   

      返回一个BigDecimal,其值是此BigDecimal的绝对值,并根据上下文设置进行舍入。

      代码示例,


   
   
  1. @Test
  2. public void testAbs () {
  3. BigDecimal a = new BigDecimal( "1.234");
  4. BigDecimal b = new BigDecimal( "-1.234");
  5. System.out.println( "1.234的绝对值:" + a.abs());
  6. System.out.println( "-1.234的绝对值:" + b.abs());
  7. System.out.println( "-1.234的绝对值,保留两位有效数字:" + b.abs( new MathContext( 2)));
  8. }

       打印结果为:

1.234的绝对值:1.234
-1.234的绝对值:1.234
-1.234的绝对值,保留两位有效数字:1.2

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值