共计 2770 个字符,预计需要花费 7 分钟才能阅读完成。
和 BigInteger
类似,BigDecimal
可以表示一个任意大小且精度完全准确的浮点数。
BigDecimal bd = new BigDecimal("123.4567");
System.out.println(bd.multiply(bd)); // 15241.55677489
BigDecimal
用 scale()
表示小数位数,例如:
BigDecimal d1 = new BigDecimal("123.45");
BigDecimal d2 = new BigDecimal("123.4500");
BigDecimal d3 = new BigDecimal("1234500");
System.out.println(d1.scale()); // 2, 两位小数
System.out.println(d2.scale()); // 4
System.out.println(d3.scale()); // 0
通过 BigDecimal
的stripTrailingZeros()
方法,可以将一个 BigDecimal
格式化为一个相等的,但去掉了末尾 0 的BigDecimal
:
BigDecimal d1 = new BigDecimal("123.4500");
BigDecimal d2 = d1.stripTrailingZeros();
System.out.println(d1.scale()); // 4
System.out.println(d2.scale()); // 2, 因为去掉了 00
BigDecimal d3 = new BigDecimal("1234500");
BigDecimal d4 = d3.stripTrailingZeros();
System.out.println(d3.scale()); // 0
System.out.println(d4.scale()); // -2
如果一个 BigDecimal
的scale()
返回负数,例如,-2
,表示这个数是个整数,并且末尾有 2 个 0。
可以对一个 BigDecimal
设置它的scale
,如果精度比原始值低,那么按照指定的方法进行四舍五入或者直接截断:
import java.math.BigDecimal;
import java.math.RoundingMode;
----
public class Main {public static void main(String[] args) {BigDecimal d1 = new BigDecimal("123.456789");
BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // 四舍五入,123.4568
BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN); // 直接截断,123.4567
System.out.println(d2);
System.out.println(d3);
}
}
对 BigDecimal
做加、减、乘时,精度不会丢失,但是做除法时,存在无法除尽的情况,这时,就必须指定精度以及如何进行截断:
BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("23.456789");
BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留 10 位小数并四舍五入
BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽
还可以对 BigDecimal
做除法的同时求余数:
import java.math.BigDecimal;
----
public class Main {public static void main(String[] args) {BigDecimal n = new BigDecimal("12.345");
BigDecimal m = new BigDecimal("0.12");
BigDecimal[] dr = n.divideAndRemainder(m);
System.out.println(dr[0]); // 102
System.out.println(dr[1]); // 0.105
}
}
调用 divideAndRemainder()
方法时,返回的数组包含两个 BigDecimal
,分别是商和余数,其中商总是整数,余数不会大于除数。我们可以利用这个方法判断两个BigDecimal
是否是整数倍数:
BigDecimal n = new BigDecimal("12.75");
BigDecimal m = new BigDecimal("0.15");
BigDecimal[] dr = n.divideAndRemainder(m);
if (dr[1].signum() == 0) {// n 是 m 的整数倍}
比较 BigDecimal
在比较两个 BigDecimal
的值是否相等时,要特别注意,使用 equals()
方法不但要求两个 BigDecimal
的值相等,还要求它们的 scale()
相等:
BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("123.45600");
System.out.println(d1.equals(d2)); // false, 因为 scale 不同
System.out.println(d1.equals(d2.stripTrailingZeros())); // true, 因为 d2 去除尾部 0 后 scale 变为 3
System.out.println(d1.compareTo(d2)); // 0 = 相等, -1 = d1 < d2, 1 = d1 > d2
必须使用 compareTo()
方法来比较,它根据两个值的大小分别返回负数、正数和0
,分别表示小于、大于和等于。
注意
总是使用 compareTo()比较两个 BigDecimal 的值,不要使用 equals()!
如果查看 BigDecimal
的源码,可以发现,实际上一个 BigDecimal
是通过一个 BigInteger
和一个 scale
来表示的,即 BigInteger
表示一个完整的整数,而 scale
表示小数位数:
public class BigDecimal extends Number implements Comparable<BigDecimal> {private final BigInteger intVal;
private final int scale;
}
BigDecimal
也是从 Number
继承的,也是不可变对象。
小结
BigDecimal
用于表示精确的小数,常用于财务计算;
比较 BigDecimal
的值是否相等,必须使用 compareTo()
而不能使用equals()
。