文章目录
1、什么是BigDecimal?
BigDecimal属于java.math
包,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。
float和double只能用来做科学计算或者是工程计算,在商业计算中(如金融行业)要用java.math.BigDecimal。
BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算
,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
2、为什么使用BigDecimal?
我们看如下代码:
public static void main(String[] args) throws Exception {
System.out.println(0.2 + 0.1);
System.out.println(0.3 - 0.1);
System.out.println(0.2 * 0.1);
System.out.println(0.3 / 0.1);
}
打印结果:
为何会这样?
原因:不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度。
根本原因:十进制值通常没有完全相同的二进制表示形式;十进制数的二进制表示形式可能不精确。只能无限接近于那个值。
但是,在项目中,我们不可能让这种情况出现,特别是金融项目,因为涉及金额的计算都必须十分精确,否则,如果你的微信账户余额显示193.99999999999998,那是一种怎么样的体验?
3、如何使用BigDecimal?
(1)BigDecimal初始化赋值
方法 | 类型 | 描述 |
---|---|---|
public BigDecimal(int val) | 构造函数 | int类型的值生成BigDecimal对象 |
public BigDecimal(long val) | 构造函数 | long类型的值生成BigDecimal对象 |
public BigDecimal(String val) | 静态方法 | String类型的值转换为BigDecimal类型 |
public static BigDecimal valueOf(double val) | 静态方法 | double类型的值转换为BigDecimal类型 |
public static BigDecimal valueOf(long val) | 静态方法 | long类型(包含int类型)的值转换为BigDecimal类型 |
代码示例:
BigDecimal b = new BigDecimal("25");
BigDecimal c = new BigDecimal(12);
System.out.println(b);
System.out.println(c);
打印结果:
注意:不建议使用public BigDecimal(double val)方式初始化值
如下代码:
BigDecimal c = new BigDecimal(12.3);
System.out.println(c);
打印结果:
如图,也会出现计算的错误。
通常建议优先使用String构造方法。当double必须用作BigDecimal的源时,请使用Double.toString(double)转成String,然后使用String构造方法,或使用BigDecimal的静态方法valueOf:
BigDecimal b = new BigDecimal("12.3");
BigDecimal c = BigDecimal.valueOf(7.34325);
BigDecimal d = new BigDecimal(Double.toString(7.34325));
System.out.println(b);
System.out.println(c);
System.out.println(d);
打印结果:
(2)加减乘除运算
运算法则 | 对应方法 | |
---|---|---|
加法 | public BigDecimal add(BigDecimal value) | |
减法 | public BigDecimal subtract(BigDecimal value) | |
乘法 | public BigDecimal multiply(BigDecimal value) | |
除法 | public BigDecimal divide(BigDecimal value) |
代码示例:
public static void main(String[] args) throws Exception {
System.out.println("计算加法: " + BigDecimal.valueOf(1.9).add(BigDecimal.valueOf(0.2)));
System.out.println("计算减法: " + BigDecimal.valueOf(1.9).subtract(BigDecimal.valueOf(1.5)));
System.out.println("计算乘法: " + BigDecimal.valueOf(1.9).multiply(BigDecimal.valueOf(0.2)));
System.out.println("计算除法: " + BigDecimal.valueOf(1.9).divide(BigDecimal.valueOf(0.2)));
}
打印结果:
注意点:
- BigDecimal的运算结果都是返回了一个新的BigDecimal对象,并不是在原有的对象上进行操作。
代码示例:
public static void main(String[] args) {
BigDecimal bigDecimal = new BigDecimal("2");
System.out.println("bigDecimal计算前的地址是:"+System.identityHashCode(bigDecimal));
bigDecimal = bigDecimal.add(BigDecimal.valueOf(3));
System.out.println("bigDecimal计算后的地址是:"+System.identityHashCode(bigDecimal));
}
打印结果:
- 使用divide除法函数除不尽,出现无线循环小数的时候,就需要使用另外精确的小数位数以及舍入模式,不然会出现报错。
代码示例:
public static void main(String[] args) {
BigDecimal a = BigDecimal.valueOf(10), b = BigDecimal.valueOf(3);
System.out.println(a.divide(b));
}
报错如下:
解决方法可以采用四舍五入的方式,详情见下文!
(3)BigDecimal保留两位小数及舍入模式
public BigDecimal setScale(int newScale, int roundingMode)
用于格式化小数的方法,第一个值表示保留几位小数,第二个值表示格式化的类型。
8种类型如下:
格式化类型 | 描述 | |
---|---|---|
ROUND_DOWN | 舍弃多余位数,如1.55会格式化为1.5,-1.55会格式化为-1.5 | |
ROUND_UP | 进位处理,如1.52会格式化为1.6,-1.52会格式化为-1.6 | |
ROUND_HALF_UP | 四舍五入,如果舍弃部分>= .5,则进位 | |
ROUND_HALF_DOWN | 五舍六入,如果舍弃部分> .5,则进位 | |
ROUND_CEILING | 正无穷大方向舍入模式。如果值为正数,则与ROUND_UP模式相同;如果值为负数,则与ROUND_DOWN模式相同 | |
ROUND_FLOOR | 负无穷大方向舍入模式。如果值为正数,则与ROUND_DOWN模式相同;如果值为负数,则与ROUND_UP模式相同 | |
ROUND_UNNECESSARY | 确认值的小数位数是否与传入第一个参数(保留小数的位数)相等,如果符合则返回值,如果不符抛出异常 | |
ROUND_HALF_EVEN | 如果舍弃部门左边的数字为奇数,则与ROUND_HALF_UP模式相同,如果为偶数则与ROUND_HALF_DOWN模式相同 |
代码示例:
public static void main(String[] args) {
BigDecimal a = BigDecimal.valueOf(5.445);
System.out.println("5.445舍弃多余位数:" + a.setScale(2, BigDecimal.ROUND_DOWN));
System.out.println("5.445进位处理:" + a.setScale(2, BigDecimal.ROUND_UP));
System.out.println("5.445四舍五入(舍弃部分>= .5,进位):" + a.setScale(2, BigDecimal.ROUND_HALF_UP));
System.out.println("5.445四舍五入(舍弃部分未> .5,舍弃):" + a.setScale(2, BigDecimal.ROUND_HALF_DOWN));
System.out.println("5.446四舍五入(舍弃部分> .5,进位):" + BigDecimal.valueOf(5.446).setScale(2, BigDecimal.ROUND_HALF_DOWN));
}
打印结果:
(4)BigDecimal比较大小
public int compareTo(BigDecimal val)
BigDecimal类提供的比较值的方法,注意比较的两个值均不能为空。
a.compareTo(b)得到结果 1, 0, -1。
比较结果 | 描述 | |
---|---|---|
1 | a 大于b | |
0 | a 等于b | |
-1 | a 小于b |
代码示例:
public static void main(String[] args) {
BigDecimal a = BigDecimal.valueOf(1);
BigDecimal b = BigDecimal.valueOf(2);
BigDecimal c = BigDecimal.valueOf(1);
BigDecimal d = BigDecimal.ZERO;
System.out.println("1和2比较结果:" + a.compareTo(b));
System.out.println("1和1比较结果:" + a.compareTo(c));
System.out.println("1和0比较判断:" + (a.compareTo(d) > 0) );
}
打印结果:
注意:实际业务中,不会单纯的比较谁打谁小,而是类似于第三条去判断一个布尔值。
(5)BigDecimal其他方法及常量
代码 | 类型 | 描述 |
---|---|---|
BigDecimal.ZERO | 常量 | 初始化一个为0的BigDecimal对象 |
BigDecimal.ONE | 常量 | 初始化一个为1的BigDecimal对象 |
BigDecimal.TEN | 常量 | 初始化一个为10的BigDecimal对象 |
public BigDecimal abs() | 方法 | 求绝对值,不管正数还是负数,都得到正数 |
public BigDecimal negate() | 方法 | 求相反数,正变负,负变正 |
public BigDecimal pow(int n) | 方法 | 求乘方,如BigDecimal.valueOf(2).pow(3)的值为8 |
public BigDecimal max(BigDecimal val) | 方法 | 两值比较,返回最大值 |
public BigDecimal min(BigDecimal val) | 方法 | 两值比较,返回最小值 |