BigDecimal的使用
概述
BigDecimal是Java在java.math
包中提供的一个API类,主要用于对超过16位有效位的数进行精确的运算。在商业计算、金融计算等需要高精度数值处理的场景中,BigDecimal显得尤为重要。但是BigDecimal是一个对象,不能直接使用传统的+、-、*、/等算术运算符进行数学运算,而必须调用其相对应的方法。本文是对BigDecimal的简单介绍。
构造方法
BigDecimal提供了多个构造方法,以便根据不同的需求创建对象:
BigDecimal(int) | 使用int创建BigDecimal对象 |
BigDecimal(double) | 使用double创建BigDecimal对象,但需要注意的是,由于double类型的精度限制,这种方法可能会导致结果有一定的不可预知性,因此通常不推荐使用 |
BigDecimal(long) | 使用long创建BigDecimal对象 |
BigDecimal(String) | 使用String创建BigDecimal对象 |
加、减、乘、除四则运算
1. BigDecimal加法
add(BigDecimal)
2. BigDecimal减法
subtract(BigDecimal)
3. BigDecimal乘法
multiply(BigDecimal)
4. BigDecimal除法
divide(BigDecimal)
对于除法需要注意的是,除法运算时可能会出现无法除尽的情况,此时需要指定保留的小数位数和舍入模式,否则会抛出ArithmeticException异常。
一下是除法使用的3种情况:
//1.可以除尽不抛异常
new BigDecimal(1).divide(new BigDecimal(2));
//2.存在除不尽的情况抛ArithmeticException异常
new BigDecimal(1).divide(new BigDecimal(3));
//java.lang.ArithmeticException: Non-terminating decimal expansion;
//no exact representable decimal result.
//3.传入四舍五入,保留两位有效数字
new BigDecimal(1).divide(new BigDecimal(3),2,BigDecimal.ROUND_HALF_UP);
使用示例
//计算表达式:3+4*5-6/2 = 20
BigDecimal v2 = new BigDecimal(2);
BigDecimal v3 = new BigDecimal(3);
BigDecimal v4 = new BigDecimal(4);
BigDecimal v5 = new BigDecimal(5);
BigDecimal v6 = new BigDecimal(6);
BigDecimal v = v3.add(v4.multiply(v5)).subtract(v6.divide(v2));
System.out.println(v);
需要注意的是BigDecimal加减乘除的执行顺序与它们的算数优先级无关,只和方法的调用顺序有关。
其它方法
BigDecimal比较大小
BigDecimal v2 = new BigDecimal(2);
BigDecimal v3 = new BigDecimal(3);
System.out.println(v2.compareTo(v3));
BigDecimal比较大小使用compareTo()方法,如v2.compareTo(v3):v2和v3相等返回0,v2大于v3返回1,v2小于v3返回-1。
注意不要使用equals()比较BigDecimal的大小,在进行等值比较时,由于BigDecimal的equals()方法会同时比较值的大小和精度,因此可能会与预期不符。如下面两个值会被判定为不相等。
BigDecimal v1 = new BigDecimal("1.0");
BigDecimal v2 = new BigDecimal("1.00");
System.out.println(v1.equals(v2));
//输出false
绝对值
abs()
浮点数初始化
浮点数初始化可以使用BigDecimal.valueOf(),浮点数初始化可能会又精度问题,使用BigDecimal.valueOf()方法则不会有问题,看看它的源码就知道了,实际上是内部把double类型转成了String类型,所以才能安全地初始化。
public static BigDecimal valueOf(double var0) {
return new BigDecimal(Double.toString(var0));
}
舍入模式
BigDecimal共有8种舍入模式:
ROUND_UP
向远离零的方向舍入。舍弃非零部分,并将非零舍弃部分相邻的一位数字加一。
ROUND_DOWN
向接近零的方向舍入。舍弃非零部分,同时不会非零舍弃部分相邻的一位数字加一,采取截取行为。
ROUND_CEILING
向正无穷的方向舍入。如果为正数,舍入结果同 ROUND_UP 一致;如果为负数,舍入结果同 ROUND_DOWN 一致。注意:此模式不会减少数值大小。
ROUND_FLOOR
向负无穷的方向舍入。如果为正数,舍入结果同 ROUND_DOWN 一致;如果为负数,舍入结果同 ROUND_UP 一致。注意:此模式不会增加数值大小。
ROUND_HALF_UP
向 最接近的数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 >= 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。这种模式也就是我们常说的我们的 四舍五入。
ROUND_HALF_DOWN
向 最接近的数字舍入,如果与两个相邻数字的距离相等,则为向下舍入的舍入模式。如果舍弃部分 > 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。这种模式也就是我们常说的我们的五舍六入。
ROUND_HALF_EVEN
向最接近的数字舍入,如果与两个相邻数字的距离相等,则相邻的偶数舍入。如果舍弃部分左边的数字奇数,则舍入行为与 ROUND_HALF_UP 相同;如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。注意:在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。此舍入模式也称为 “银行家舍入法”,主要在美国使用。四舍六入,被舍位为 5 时两种情况,如果前一位为奇数,则入位,否则舍去。
ROUND_UNNECESSARY
断言请求的操作具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定此舍入模式,则抛出异常。
总结
综上所述,BigDecimal是Java中处理高精度数值的重要工具,通过合理使用其构造方法和数学运算方法,可以满足商业计算、金融计算等场景对高精度数值处理的需求。
参考
BigDecimal的8种RoundingMode(舍入模式)