为什么使用 BigDecimal

在日常开发中我们经常会碰到小数计算,而小数直接计算的话会出现一些小小的错误,如下

这是因为不论是 float 还是 double 都是浮点数,他们执行二进制浮点运算

而计算机是二进制的,浮点数会失去一定的精确度

所以 float 和 double 只能用来做科学计算或者是工程计算

所以如果需要精确的答案,请避免使用 float 和 double,尤其是在涉及到货币计算的时候一定要使用 BigDecimal

关于 BigDecimal

Java 在java.math包中提供的APIBigDecimal,用来对超过 16 位有效位的数进行精确的运算。

BigDecimal所创建的是对象,我们不能使用传统的 +-*/ 等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是 BigDecimal 的对象

构造器描述

构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

  • BigDecimal(int): 创建一个具有参数所指定整数值的对象
  • BigDecimal(double): 创建一个具有参数所指定双精度值的对象
  • BigDecimal(long): 创建一个具有参数所指定长整数值的对象
  • BigDecimal(String): 创建一个具有参数所指定以字符串表示的数值的对象

方法描述

  • add(BigDecimal): BigDecimal 对象中的值相加,然后返回这个对象
  • subtract(BigDecimal): BigDecimal 对象中的值相减,然后返回这个对象
  • multiply(BigDecimal): BigDecimal 对象中的值相乘,然后返回这个对象
  • divide(BigDecimal): BigDecimal 对象中的值相除,然后返回这个对象
  • doubleValue(): 将 BigDecimal 对象中的值以双精度数返回
  • floatValue(): 将 BigDecimal 对象中的值以单精度数返回
  • longValue(): 将 BigDecimal 对象中的值以长整数返回
  • intValue(): 将 BigDecimal 对象中的值以整数返回
  • setScale(): 格式化小数点

BigDecimal 的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Demo {
public static void main(String[] args) {

double d = 3.05;
String str = "3.05";

BigDecimal b1 = new BigDecimal(d);
System.out.println(b1);

BigDecimal b2 = new BigDecimal(str);
System.out.println(b2);

BigDecimal b3 = BigDecimal.valueOf(d);
System.out.println(b3);
}
}

区别

加减乘除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Demo {
public static void main(String[] args) {

// 加
System.out.println(new BigDecimal("2.005").add(new BigDecimal("0.03")));

// 减
System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));

// 乘
System.out.println(new BigDecimal("2.05").multiply(new BigDecimal("10")));

// 除
System.out.println(new BigDecimal(153.5).divide(new BigDecimal(100)));
}
}

BigDecimal 保留 N 位小数

BigDecimal.setScale(); 方法用于格式化小数点,可以自定义处理方式。

ROUND_DOWN

向零方向舍入

1
2
3
4
// 3.141
System.out.println(new BigDecimal(3.14159).setScale(3, BigDecimal.ROUND_DOWN));
// -3.141
System.out.println(new BigDecimal(-3.14159).setScale(3, BigDecimal.ROUND_DOWN));

ROUND_UP

向远离 0 的方向舍入

1
2
3
4
// 3.142
System.out.println(new BigDecimal(3.14159).setScale(3, BigDecimal.ROUND_UP));
// -3.142
System.out.println(new BigDecimal(-3.14159).setScale(3, BigDecimal.ROUND_UP));

ROUND_CEILING

向正无穷方向舍入

1
2
3
4
// 3.142
System.out.println(new BigDecimal(3.14159).setScale(3, BigDecimal.ROUND_CEILING));
// -3.141,距离正无穷更近
System.out.println(new BigDecimal(-3.14159).setScale(3, BigDecimal.ROUND_CEILING));

ROUND_FLOOR

向负无穷方向舍入

1
2
3
4
// 3.141
System.out.println(new BigDecimal(3.14159).setScale(3, BigDecimal.ROUND_FLOOR));
// -3.142
System.out.println(new BigDecimal(-3.14159).setScale(3, BigDecimal.ROUND_FLOOR));

ROUND_UNNECESSARY

计算结果是精确的,不需要舍入模式

1
2
3
4
// 3.141
System.out.println(new BigDecimal("3.141").setScale(3, BigDecimal.ROUND_UNNECESSARY));
// -3.141
System.out.println(new BigDecimal("-3.141").setScale(3, BigDecimal.ROUND_UNNECESSARY));