目录
- BigDecimal简介
- BigDecimal常用方法
- 创建BigDecimal
- 加减乘除
- 大小比较
- BigDecimal等值比较问题
- 保留小数位数
BigDecimal简介
- 浮点数之间的等值判断,基本数据类型不能用 == 来比较,包装数据类型不能用 equals 来判断。
- BigDecimal 可以实现对浮点数的运算,不会造成精度丢失;
- 通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal 来做的;
BigDecimal常用方法
创建BigDecimal
- 禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象,因为其存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
- 在使用 BigDecimal 时,为了防止精度丢失,推荐使用BigDecimal(String val)构造方法或者 BigDecimal.valueOf(double val) 静态方法来创建对象;
如:BigDecimal g = new BigDecimal(0.1),实际存储为0.1000000000000000055511151231257827021181583404541015625
推荐入参为String的构造方法,或BigDecimal的valueOf方法,此方法内部其实执行了Double的toString,而Double的toString按double实际能表达的精度对尾数进行了截断。
BigDecimal b1 = new BigDecimal(“0.1”);
BigDecimal b2 = BigDecimal.valueOf(0.1);
加减乘除
-
add
方法用于将两个BigDecimal对象相加; -
subtract
方法用于将两个BigDecimal对象相减; -
multiply
方法用于将两个BigDecimal对象相乘; -
divide
方法用于将两个BigDecimal对象相除;
使用 divide 方法的时候尽量使用 3 个参数版本,并且RoundingMode 不要选择 ROUND_UNNECESSARY,否则很可能会遇到 ArithmeticException(无法除尽出现无限循环小数的时候),其中 scale 表示要保留几位小数,roundingMode 代表保留规则。
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode);
RoundingMode枚举:
- UP:向远离零的方向舍入。若舍入位为非零,则对舍入部分的前一位数字加1;若舍入位为零,则直接舍弃;
- DOWN:向接近零的方向舍入。不论舍入位是否为零,都直接舍弃;
- CEILING:向正无穷大的方向舍入。若 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;若为负,则舍入行为与 ROUND_DOWN 相同。即为向上取整模式;
- FLOOR:向负无穷大的方向舍入。若 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;若为负,则舍入行为与 ROUND_UP 相同。即为向下取整模式。
- HALF_UP:四舍五入。若舍入位大于等于5,则对舍入部分的前一位数字加1;若舍入位小于5,则直接舍弃。
- HALF_DOWN:五舍六入。若舍入位大于5,则对舍入部分的前一位数字加1;若舍入位小于等于5,则直接舍弃。
- HALF_EVEN:银行家舍入模式。若(舍入位大于5)或者(舍入位等于5且前一位为奇数),则对舍入部分的前一位数字加1;若(舍入位小于5)或者(舍入位等于5且前一位为偶数),则直接舍弃;
- UNNECESSARY:不舍位, 精度位数小于小数位数会抛出ArithmeticException;
大小比较
a.compareTo(b)
: 返回 -1 表示 a 小于 b,0 表示 a 等于 b , 1 表示 a 大于 b。
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
System.out.println(a.compareTo(b));// 1
BigDecimal等值比较问题
BigDecimal的等值比较应使用compareTo(),而不是equals(),因为equals()会比较值和精度(1.0与1.00返回结果为false),而compareTo()会忽略精度。
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("1.0");
System.out.println(a.equals(b));//false
System.out.println(a.compareTo(b));//0
保留小数位数
setScale()方法设置保留几位小数以及保留规则。
BigDecimal m = new BigDecimal("1.255433");
BigDecimal n = m.setScale(3,RoundingMode.HALF_DOWN);
System.out.println(n);// 1.255