1、为何要用BigDecimal类
float和double在进行数学运算时偶尔会出现不精确的现象,如在使用微信支付时,要把金额单位从元转成分再传给微信,69.99元这个值会得到不精确的结果:
@Test
public void test27() throws Exception{
//元转分
Double amount = Double.parseDouble("69.99") * 100;
System.out.println(amount);//print:6998.999999999999
System.out.println(amount.intValue());//print: 6998
}
因此,针对要求精确结果的商业计算场景,要使用BigDecimal类。
2、基本用法
业务中的常见用法主要是加减乘除、大小比较、精度控制等。
2.1、加减乘除
@Test
public void test30() throws Exception{
BigDecimal a = new BigDecimal("69.99");
BigDecimal b = new BigDecimal("100");
BigDecimal add = a.add(b);
System.out.println("加法:" + add);
BigDecimal subtract = a.subtract(b);
System.out.println("减法:" + subtract);
BigDecimal multiply = a.multiply(b);
System.out.println("乘法:" + multiply);
BigDecimal divide = a.divide(b);
System.out.println("除法:" + divide);
}
print:
加法:169.99
减法:-30.01
乘法:6999.00
除法:0.6999
2.2、大小比较
BigDecimal类通过compareTo方法进行比较,大于为1,小于为-1,等于为0。
@Test
public void test31() throws Exception{
BigDecimal a = new BigDecimal("1.5");
BigDecimal b = new BigDecimal("1.6");
BigDecimal c = new BigDecimal("1.50");
System.out.println(a.compareTo(b));//print: -1
System.out.println(b.compareTo(c));//print: 1
System.out.println(a.compareTo(c));//print: 0
}
2.3、精度控制
BigDecimal类用setScale方法控制保留小数的位数。
2.3.1、小数位数
@Test
public void test32() throws Exception{
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("2");
System.out.println(a.add(b).setScale(2));//print: 3.00
//表示保留2位小数位数,默认为四舍五入方式
}
注意:当设置的精确位小于当前值的实际精确位时,存在舍入误差,此时必须指定取整模式,否则会报错。
@Test
public void test33() throws Exception{
BigDecimal a = new BigDecimal("631");
BigDecimal b = new BigDecimal("100");
System.out.println(a.divide(b).setScale(1));
}
报错如下:
java.lang.ArithmeticException: Rounding necessary
at java.math.BigDecimal.commonNeedIncrement(BigDecimal.java:4148)
at java.math.BigDecimal.needIncrement(BigDecimal.java:4204)
at java.math.BigDecimal.divideAndRound(BigDecimal.java:4112)
at java.math.BigDecimal.setScale(BigDecimal.java:2452)
at java.math.BigDecimal.setScale(BigDecimal.java:2512)
……
应设为:
setScale(1,BigDecimal.ROUND_HALF_UP)
2.3.2、精度类型
@Test
public void test34() throws Exception {
//1.四舍五入(4舍弃,5进位)
BigDecimal a = new BigDecimal("2.35").setScale(1, BigDecimal.ROUND_HALF_UP);
System.out.println("a: " + a);//print: 2.4
//2.五舍六入(5舍弃,6进位)
BigDecimal b = new BigDecimal("2.35").setScale(1, BigDecimal.ROUND_HALF_DOWN);
System.out.println("b: " + b);//print: 2.3
//3.向远离0的方向舍入
BigDecimal c = new BigDecimal("2.32").setScale(1, BigDecimal.ROUND_UP);
System.out.println("c: " + c);//print: 2.4
//4.向靠近0的方向舍入
BigDecimal d = new BigDecimal("2.38").setScale(1, BigDecimal.ROUND_DOWN);
System.out.println("d: " + d);//print: 2.3
//5.向正无穷方向舍入
BigDecimal e = new BigDecimal("2.31").setScale(1, BigDecimal.ROUND_CEILING);
System.out.println("e: " + e);//print: 2.4
//6.向负无穷方向舍入
BigDecimal f = new BigDecimal("-2.31").setScale(1, BigDecimal.ROUND_FLOOR);
System.out.println("f: " + f);//print: -2.4
}