《阿里巴巴 Java 开发手册》中提到:“为了避免精度丢失,可以使用 BigDecimal 来进行浮点数的运算”。
float/double 与 BigDecimal对比
float&double
浮点数 float 或 double 运算的时候会有精度丢失的风险
因为十进制转换为二进制时,二进制有长度限制,会有截断问题。
关于浮点数,可以看这篇文章 kaito-kidd.com/2018/08/08/…
BigDecimal
BigDecimal 可以实现对浮点数的运算,不会造成精度丢失。
通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal 来做的。
BigDecimal的使用
创建
在创建BigDecimal时为了防止精度丢失,推荐使用它的BigDecimal(String val)构造方法或者 BigDecimal.valueOf(double val) 静态方法来创建对象。 禁止使用BigDecimal(double val)来创建BigDecimal对象,否则还是有精读丢失问题。 示例:
// 建议使用
BigDecimal a = new BigDecimal("1.0");
// 禁止使用
BigDecimal a = new BigDecimal(1.0);
加减乘除
示例:
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
System.out.println(a.add(b));// 1.9
System.out.println(a.subtract(b));// 0.1
System.out.println(a.multiply(b));// 0.90
System.out.println(a.divide(b));// 无法除尽,抛出 ArithmeticException 异常
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP));// 1.11
精读保留
示例:
BigDecimal m = new BigDecimal("1.255433");
BigDecimal n = m.setScale(3,RoundingMode.HALF_DOWN);
System.out.println(n);// 1.255
比较大小
示例:
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
System.out.println(a.compareTo(b));// 1
等值比较
使用compareTo()方法,而非equals()方法。 因为 equals() 方法不仅仅会比较值的大小(value)还会比较精度(scale),而 compareTo() 方法比较的时候会忽略精度。
示例:
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("1.0");
System.out.println(a.equals(b));//false
注:
《阿里巴巴 Java 开发手册》中提到:浮点数之间的等值判断,基本数据类型不能用 == 来比较,包装数据类型不能用 equals 来判断。
转String
BigDecimal的toString()方法,在某些场景下会生成科学计数法的值;大部分情况不想要科学计数法格式,所以需要使用toPlainString()方法。
示例:
BigDecimal a = new BigDecimal("0.000000123").setScale(9);
System.out.println(a.toString()); // 1.23E-7
System.out.println(a.toPlainString()); // 0.000000123
参考文章
segmentfault.com/a/119000004…
阿里巴巴java开发手册