BigDecimal相关

留意

浮点类型

高精度之精度丢失

1
2
3
4
// 用法一
BigDecimal a = new BigDecimal(0.01);
// 用法二
BigDecimal b = BigDecimal.valueOf(0.01);

对应的结果如下:

a: 0.01000000000000000020816681711721685132943093776702880859375
b: 0.01


那么: 在new BigDecimal的时候传入的已经是浮点类型( 近似值 )了, 而在使用valueOf的时候, 通过阅读源码可知

1
2
3
public static BigDecimal valueOf(double val) {
return new BigDecimal(Double.toString(val));
}

在valueOf的方法内部, 调用了Double.toString方法转换成为了字符串, 转换成为字符串就不存在进度丢失问题 (因为可以使用字符串模拟高精度实现计算: 梦回c语言高精度实现)

那么我们需要使用则: (两个方向)

  1. 创建对象时, 构造函数传字符串
  2. 使用BigDecimal.valueOf传值初始化对象

精度设置

其实就是四舍五入的问题

1
2
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");

例如我们需要运算

1
a.divide(b);

然后就会抛出异常: ArithmeticException

因为它(结果)是一个无限循环小数, 它不能转换成为我们预期的精确数字

所以需要指定精度

1
BigDecimal c = a.divide(b, 4,RoundingMode.HALF_UP);
  • 4: 四位小数
  • RoundingMode.HALF_UP: HALF_UP-> 大于一半则向上取整

故结果为: 0.3333

其中RoundingMode还有很多枚举, 自行查阅

浮点比较

比较BigDecimal值的大小

1
2
BigDecimal a = new BigDecimal("0.01");
BigDecimal b = new BigDecimal("0.010");

然后有两种比较方法

1
2
a.equals(b)
a.compareTo(b)

其中一看好像没什么区别, 查阅源码( equals )可知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale) // 如果精度不一样,直接false
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);

return this.inflated().equals(xDec.inflated());
}

compareTo则是实现比较值的大小, 返回的值为-1(小于),0(等于),1(大于)

我们可以知道, 如果在严格要求精度的情况下, 使用equals

如果仅考虑值的大小则考虑使用 compareTo

输出格式化

此处仅给出几个示例:

1
2
3
4
5
6
7
8
9
10
11
NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用
NumberFormat percent = NumberFormat.getPercentInstance(); //建立百分比格式化引用
percent.setMaximumFractionDigits(4); //百分比小数点最多4位

BigDecimal loanAmount = new BigDecimal("59988.24"); //金额
BigDecimal interestRate = new BigDecimal("0.007"); //利率
BigDecimal interest = loanAmount.multiply(interestRate); //相乘

System.out.println("金额:\t" + currency.format(loanAmount));
System.out.println("利率:\t" + percent.format(interestRate));
System.out.println("利息:\t" + currency.format(interest));

输出:

1
2
3
金额: ¥59,988.24 
利率: 0.7%
利息: ¥419.92