在进行浮点型运算时,直接使用“ + - * / ”可能会出现运算结果失真,例如:
System.out.println(0.1 + 0.2); System.out.println(1.0 - 0.32); System.out.println(1.015 * 100); System.out.println(1.301 / 100);
运行结果:
诸如这些情况,就是出现了结果失真的问题。
BigDecimal类就是为了解决这个问题的。
BigDecimal
- 用于解决浮点型运算时,出现结果失真的问题。
BigDecimal的常见构造器、常用方法
构造器 | 说明 |
public BigDecimal(double val) 注意:不推荐使用这个 | 将double转换为BigDecimal |
public BigDecimal(String val) | 把string转成BigDecimal |
用法示例
public class Test { public static void main(String[] args) { double a = 0.1; double b = 0.2; // BigDecimal a1 = new BigDecimal(Double.toString(a)); // BigDecimal b1 = new BigDecimal(Double.toString(b)); //推荐使用以下方式,把小数转换成字符串再得到BigDecimal对象来使用(更简洁) BigDecimal a1 = BigDecimal.valueOf(a); BigDecimal b1 = BigDecimal.valueOf(b); BigDecimal c1 = a1.add(b1); System.out.println(c1); } }
运行结果:
(没有出现运算结果失真)
其他方法
public class Test { public static void main(String[] args) { double a = 0.1; double b = 0.2; // BigDecimal a1 = new BigDecimal(Double.toString(a)); // BigDecimal b1 = new BigDecimal(Double.toString(b)); //推荐使用以下方式,把小数转换成字符串再得到BigDecimal对象来使用(更简洁) BigDecimal a1 = BigDecimal.valueOf(a); BigDecimal b1 = BigDecimal.valueOf(b); BigDecimal c1 = a1.add(b1); System.out.println(c1); BigDecimal c2 = a1.subtract(b1); //减法 BigDecimal c3 = a1.multiply(b1); //乘法 BigDecimal c4 = a1.divide(b1); //除法 System.out.println(c2); System.out.println(c3); System.out.println(c4); } }
运行结果:
注意:对于除法,如果无法除尽,会因无法确定精度而报错。
public class Test { public static void main(String[] args) { BigDecimal i = BigDecimal.valueOf(0.1); BigDecimal j = BigDecimal.valueOf(0.3); BigDecimal k = i.divide(j); //除不尽 } }
解决办法:
public class Test { public static void main(String[] args) { BigDecimal i = BigDecimal.valueOf(0.1); BigDecimal j = BigDecimal.valueOf(0.3); // BigDecimal k = i.divide(j); //除不尽 BigDecimal k = i.divide(j,2, RoundingMode.HALF_UP); //这里的RoundingMode.HALF_UP是一个枚举类里的常量,代表四舍五入 System.out.println(k); } }
这样运行结果就正常了,(保留两位小数) 但是一般还是用double来解决这种问题
再来示例一下,把BigDecimal对象转换成double类型的数据
public class Test { public static void main(String[] args) { BigDecimal i = BigDecimal.valueOf(0.1); BigDecimal j = BigDecimal.valueOf(0.3); // BigDecimal k = i.divide(j); //除不尽 BigDecimal k = i.divide(j,2, RoundingMode.HALF_UP); //这里的RoundingMode.HALF_UP是一个枚举类里的常量,代表四舍五入 //把BigDecimal对象转换成doubLe类型的数据 double rs = k.doubleValue(); System.out.println(rs); } }
运行结果: 已转换为double类型
使用规范
提及其中的一点: (取自Java开发手册)
禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象。
说明:BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
如:BigDecimal g = new BigDecimal(0.1F); 实际的存储值为:0.10000000149
正例 优先推荐入参为String的构造方法去,或使用BigDecinal的valueOf方法,此方法内部其实执行了Double的toString,而Double的toString按double的实际能表达的精度对尾数进行了截断。
END