java浮点数精度丢失无法完全避免,应根据场景选择bigdecimal或整数化处理:金融等场景用bigdecimal(字符串构造、指定舍入模式),固定单位业务转为整数运算,double比较需用误差范围而非==。

Java 中浮点数运算精度丢失无法完全避免,但可通过合适策略控制误差、满足业务精度要求。关键不是否认 double/float 的局限,而是根据场景选择更可靠的表达或计算方式。
优先使用 BigDecimal 进行精确十进制计算
金融、计费、配置值等对小数点后位数敏感的场景,应避免用 double 直接加减乘除。BigDecimal 虽有性能开销,但能明确控制舍入行为和精度。
- 构造时用字符串而非 double 字面量: new BigDecimal("0.1") ✅,new BigDecimal(0.1) ❌(后者会先引入 double 误差)
- 指定舍入模式,如 RoundingMode.HALF_UP(四舍五入),避免默认的 UNNECESSARY 导致异常
- 运算后调用 setScale(2, RoundingMode.HALF_UP) 统一保留两位小数,再转成字符串或 int 表示分
整数化处理:把小数转为整数运算
若业务单位固定(如金额单位为“分”、温度精度到 0.01℃),可将数值放大为整数参与计算,彻底规避浮点误差。
- 0.15 元 → 存为 15(单位:分),所有加减乘除都在 long 或 int 上进行
- 显示或传输前再除以 100.0 并格式化,或用 String.format("%.2f", value / 100.0)
- 注意溢出风险:大数乘法可能超出 int 范围,建议用 long 或提前检查
容忍误差的比较与判断
当必须用 double 做中间计算(如科学计算、图形渲染),不应用 == 判断相等,而应定义可接受的误差范围(epsilon)。
- 写成 Math.abs(a - b) 替代 a == b
- epsilon 大小需结合业务量级:1e-6 适合普通数值,1e-15 对 double 本身意义不大(受尾数位限制)
- 涉及累加时误差会累积,可考虑每若干次重新用 BigDecimal 校准一次
避免无意义的高精度输出
double 本身是二进制近似表示,打印或日志中直接 toString() 可能暴露隐藏误差(如 0.1 + 0.2 输出 0.30000000000000004)。应按需格式化。
- 用 String.format("%.2f", d) 或 DecimalFormat 控制显示位数
- JSON 序列化时,Jackson 等库默认会截断冗余小数位;若需严格控制,可自定义序列化器
- 不要依赖 toString() 结果做逻辑判断,它反映的是内部表示,不是数学值
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











