java浮点数运算不精确源于ieee 754二进制表示无法精确存储多数十进制小数,如0.1+0.2≠0.3;应使用bigdecimal字符串构造、调用add/multiply等方法、指定舍入模式和标度,避免double参数及基本类型混合运算。

Java 中浮点数(float、double)运算不精确,根本原因是它们基于二进制 IEEE 754 标准表示小数,而很多十进制小数(如 0.1)无法被精确表示为有限位二进制小数,导致计算结果存在微小误差。例如 0.1 + 0.2 得到 0.30000000000000004,而非预期的 0.3。
用 BigDecimal 构造时避免 double 参数
这是最常见的陷阱:直接用 double 值构造 BigDecimal,会把 double 本身的精度误差一并带入。
❌ 错误写法:
BigDecimal a = new BigDecimal(0.1); // 实际传入的是 0.10000000000000000555... BigDecimal b = new BigDecimal(0.2); System.out.println(a.add(b)); // 输出:0.30000000000000001665...
✅ 正确写法:使用字符串构造,确保字面量精度无损。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用字符串字面量:
new BigDecimal("0.1")、new BigDecimal("123.45") - 或从整数/长整型按比例换算:
BigDecimal.valueOf(1, 1)等价于"0.1"(但更推荐字符串) - 避免一切含
double或float字面量的构造方式
所有运算都用 BigDecimal 的方法,不用基本类型混合
BigDecimal 是不可变对象,所有算术操作必须调用其方法(如 add、multiply),并接收另一个 BigDecimal 参数。不能直接用 +、*,也不能混用 int/double。
- 加法:
a.add(b),不是a + b - 乘法:
a.multiply(b),注意乘法后小数位数是两者之和,需留意精度控制 - 除法:
a.divide(b, scale, RoundingMode.HALF_UP)—— 必须指定小数位数和舍入模式,否则可能抛ArithmeticException - 比较用
compareTo()(返回 -1/0/1),不要用==或equals()(后者会比较标度,"1.0"和"1.00"不等)
合理设置小数位数与舍入模式
金融、计费等场景对精度和舍入规则有明确要求(如“四舍五入保留两位小数”)。BigDecimal 提供了灵活的标度(scale)和舍入策略支持。
- 常用舍入模式:
RoundingMode.HALF_UP(最接近的舍入,0.5 向上,即日常“四舍五入”) - 设置标度:
result.setScale(2, RoundingMode.HALF_UP) - 除法务必显式指定:
money.divide(unitPrice, 2, RoundingMode.HALF_UP) - 避免无参数
divide(),它要求结果能整除,否则抛异常
实际使用建议与注意事项
BigDecimal 解决了精度问题,但带来性能开销和代码冗余。它适合对精度敏感的场景(金额、科学计算),不适合高频循环或实时性要求极高的场合。
- 输入源头就用字符串:用户输入、配置文件、数据库读取的数值字段,优先转为
String再构造成BigDecimal - 输出时格式化用
toString()或toPlainString()(避免科学计数法),不要用doubleValue()回转 - 初始化常量可复用静态实例,如
private static final BigDecimal ZERO = new BigDecimal("0"); - 注意内存和 GC:频繁创建大量
BigDecimal对象会影响性能,必要时考虑对象池(但一般不需要)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










