BigDecimal介绍

一、常用函数:

BigDecimal num12 = new BigDecimal("0.005");
BigDecimal num22 = new BigDecimal("1000000");
BigDecimal num32 = new BigDecimal("-1000000");

加法 add()函数 :

BigDecimal result12 = num12.add(num22);//1000000.005

减法subtract()函数

BigDecimal result22 = num12.subtract(num22);//999999.995

乘法multiply()函数

BigDecimal result32 = num12.multiply(num22);//5000.000

绝对值abs()函数

BigDecimal result42 = num32.abs();//1000000

除法divide()函数

BigDecimal result52 = num22.divide(num12,20,BigDecimal.ROUND_HALF_UP);

使用除法函数在divide的时候要设置各种参数,要精确的小数位数和舍入模式,不然会出现报错,我们可以看到divide函数配置的参数如下:
(BigDecimal divisor 除数, int scale 精确小数位, int roundingMode 舍入模式)

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

八种舍入模式解释如下

  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。

二、使用BigDecimal需要注意的几点

1.new BigDecimal() 还是 BigDecimal.valueOf()

尽量要使用字符串而不是浮点数去构造 BigDecimal 对象,如果实在不行,就使用 BigDecimal.valueOf() 方法:

BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = BigDecimal.valueOf(0.01);
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);

输出到控制台的结果是:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

造成这种差异的原因是 0.1 这个数字计算机是无法精确表示的,送给 BigDecimal 的时候就已经丢精度了,而 BigDecimal.valueOf 的实现却完全不同

public static BigDecimal valueOf(double val) {
    // Reminder: a zero double returns '0.0', so we cannot fastpath
    // to use the constant ZERO.  This might be important enough to
    // justify a factory approach, a cache, or a few private
    // constants, later.
    return new BigDecimal(Double.toString(val));
}

还可以用new BigDecimal(0)的方式将基础类型的数字转为BigDecimal:比如初始化为0,用

BigDecimal d = new BigDecimal("0")

new BigDecimal(0)有可能得到的是0.000000000000001之类的值,这是Java的bug。初始化0或者其他基础类型数字转换为BigDecimal最好用字符串。

2.等值比较

BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("1.00");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2));

控制台的输出将会是:

false
0

究其原因是,BigDecimal 中 equals 方法的实现会比较两个数字的精度,而 compareTo 方法则只会比较数值的大小。

3.BigDecimal 并不代表无限精度

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
a.divide(b)

结果会抛出异常:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

大概就是说,如果除法的商的结果是一个无限小数但是我们期望返回精确的结果,那程序就会抛出异常。
可改为如下输出:输出结果为0.03

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
a.divide(b, 2, RoundingMode.HALF_UP)// 0.33

4.BigDecimal转回String的三种方法:

String toString();     // 有必要时使用科学计数法  如1.23345353454567E+16
String toPlainString();   // 不使用科学计数法
String toEngineeringString();  // 工程计算中经常使用的记录数字的方法,与科学计数法类似,但要求10的幂必须是3的倍数

5.执行顺序不能调换(乘法交换律失效)
BigDecimal 的乘除计算,不遵循乘法交换律,按照从前到后的顺序进行计算:

BigDecimal a = BigDecimal.valueOf(1.0);
BigDecimal b = BigDecimal.valueOf(3.0);
BigDecimal c = BigDecimal.valueOf(3.0);
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP).multiply(c)); // 0.990
System.out.println(a.multiply(c).divide(b, 2, RoundingMode.HALF_UP));// 1.0

输出结果:

0.990
1.0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值