Java学习笔记:BigDecimal


本篇文章是自己学习的总结。


BigDecimal舍弃小数

BigDecimal中将小数精确到多少位的操作有很多,可以基于四舍五入,可以暴力截断,也可以只要有小数直接进位等等,有多种方式,下面就说一下有哪些精确小数的方式。

BigDecimal中精确到几位小数是通过setScale(int scale,RoundingMode roundingMode)这个函数实现的,所以理解了这个函数就理解了BigDecimal是如何对小数精确的。

第一个参数scale比较简单,想将小数精确到几位,scalse就等于几。

第二个参数RoundingMode决定的是如何对小数进行精确,这是重点讲解的部分。roundIngMode是定义好的枚举类,他有以下几个值ROUND_UP,ROUND_DOWN,ROUND_CEILING,ROUND_FLOOR,ROUND_HALF_UP,ROUND_HALF_DOWN,ROUND_HALF_EVEN。这些枚举类的效果如下图所示(图片来源Java文档)

注意一下,Java中也有setScalse(int scale,int roundingRode)的函数,但这个函数被弃用了,BigDecimal.CEILING等静态变量不如枚举类安全。

  • ROUND_CEILING

这是直接向正无穷大进位。比如

      BigDecimal("32.21").setScale(1, RoundingMode.CEILING) = 32.3;
      BigDecimal("32.26").setScale(1, RoundingMode.CEILING) = 32.3;

而负数也是向正无穷大进位所以

      BigDecimal("-32.21").setScale(1, RoundingMode.CEILING) = -32.2;
      BigDecimal("-32.29").setScale(1, RoundingMode.CEILING) = -32.2;
  • ROUND_FLOOR

它ROUND_CEILING相反,它是向负无穷大进位,比如

      BigDecimal("32.21").setScale(1, RoundingMode.FLOOR) = 32.2;
      BigDecimal("32.26").setScale(1, RoundingMode.FLOOR) = 32.2;

而负数向负无穷大进位的情况如下

      BigDecimal("-32.21").setScale(1, RoundingMode.FLOOR) = -32.3;
      BigDecimal("-32.29").setScale(1, RoundingMode.FLOOR) = -32.3;
  • ROUND_DOWN

这是让小数向零的方向进位,比如

      BigDecimal("32.21").setScale(1, RoundingMode.DOWN) = 32.2;
      BigDecimal("32.28").setScale(1, RoundingMode.DOWN) = 32.2;

而负数的情况就是

      BigDecimal("-32.21").setScale(1, RoundingMode.DOWN) = -32.2;
      BigDecimal("-32.29").setScale(1, RoundingMode.DOWN) = -32.2;
  • ROUND_UP

和ROUND_DOWN相反,它是向远离零的方向进位

      BigDecimal("32.21").setScale(1, RoundingMode.UP) = 32.3;
      BigDecimal("32.28").setScale(1, RoundingMode.UP) = 32.3;

而负数的情况是

      BigDecimal("-32.21").setScale(1, RoundingMode.UP) = -32.3;
      BigDecimal("-32.28").setScale(1, RoundingMode.UP) = -32.3;
  • ROUND_HALF_UP

这个规则就是常见的四舍五入进位了

      BigDecimal("32.25").setScale(1, RoundingMode.HALF_UP) = 32.3;
      BigDecimal("-32.25").setScale(1, RoundingMode.HALF_UP) = -32.3;
  • ROUND_HALF_DOWN

它和四舍五入比较像,不同点是,它是五舍六入

BigDecimal("32.25").setScale(1, RoundingMode.HALF_DOWN) = 32.2;
BigDecimal("-32.25").setScale(1, RoundingMode.HALF_DOWN) = -32.2;
  • ROUND_HALF_EVEN

这也是和四舍五入比较像,但是它的进位有些不一样。该进位模式也被称为银行家舍入,它是像偶数位进位。

比如下面的小数位已经达到5,这是需要进位的,所以精确位进“进位”到偶数的位置。

BigDecimal("32.25").setScale(1, RoundingMode.HALF_EVEN) = 32.2;

而另一个例子

      BigDecimal("32.35").setScale(1, RoundingMode.HALF_DOWN) = 32.4;

而精确位的后一位的数值小于5的话,就向奇数方向进位。


divide方法

大数中涉及到除法就会有很多问题,比如无限小数怎么显示。这里将详细说一下使用divide方法时的注意事项。

下面说一下divide的几种重载形式。

  • BigDecimal divide(BigDecimal divisor)

这个方法只有一个点是需要注意的,它没法应对结果是无限小数的情况。比如下面的代码会直接报异常

BigDecimal temp = new BigDecimal("10");
System.out.println(temp.divide(BigDecimal.valueOf(3)));

divisor是被除数,scale是精确到小数后的多少位,roundingMode就是上文介绍的采用哪种模式进行小数的精确。比如下面的例子

BigDecimal temp = new BigDecimal("32.21");
System.out.println(temp.divide(BigDecimal.valueOf(0.3), RoundingMode.CEILING));

输出结果为

同样的,关于RoundingMode roundingMode这个参数,Java仍然提供int roundingMode的形式,不过是被弃用的,一定要使用RoundingMode枚举类。

这个方法和上个方法相同,只是不指明精确到小数多少位。这个函数其实是默认scale和调用这个方法的BigDecimal的scale相等。源码中是这样的

return divide(this.intCompact, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode);

它直接将调用者的scale赋值给结果的scale。比如

BigDecimal temp = BigDecimal.valueOf(32.21);  //这个初始化会将scale赋值为2,和32.21的scale相同

那么

BigDecimal result = temp.divide(BigDecimal.valueOf(3.0), RoundingMode.CEILING);

其中的result的scale和temp相同,也是等于2。

猜你喜欢

转载自blog.csdn.net/sinat_38393872/article/details/102794037