java浮点数精度丢失本质是二进制无法精确表示十进制小数,属ieee 754设计特性;应合理规避——金额等场景用bigdecimal(推荐字符串构造),浮点比较用误差范围,优先选用整数单位,理解double适用边界。

Java 中浮点数精度丢失本质是二进制无法精确表示大多数十进制小数,float 和 double 都基于 IEEE 754 标准存储,不是 bug,而是设计使然。关键不在于“修复”,而在于“合理规避”和“正确选用类型”。
用 BigDecimal 做精确十进制计算
涉及金额、计费、科学测量等要求精确十进制结果的场景,必须用 BigDecimal。它以字符串或整数构造最安全,避免 double 构造器引入初始误差。
- ✅ 推荐写法:new BigDecimal("0.1") 或 BigDecimal.valueOf(0.1)(后者内部用字符串转换)
- ❌ 避免写法:new BigDecimal(0.1) —— 此时传入的 double 0.1 已经是近似值,误差已固化
- 运算记得用 add()、subtract()、multiply()、divide(scale, roundingMode),不要用 + - * /
比较浮点数别用 ==,改用误差范围判断
两个 double 相等性不能直接用 == 判断,应设定一个极小容差(epsilon)进行区间比较。
- 简单判断:Math.abs(a - b)
- 更鲁棒可封装为工具方法,考虑相对误差(尤其当 a、b 很大或很小时)
- JUnit 中推荐用 assertEquals(expected, actual, delta)
能用整数就别用浮点数
很多业务场景其实可以规避浮点:比如金额统一用“分”为单位存 long 或 int;比例用百分比整数(如 95 表示 95%);时间用毫秒或纳秒长整型。
- 优势:无精度问题、性能高、序列化/传输更稳定
- 注意:做除法后需明确舍入策略(如四舍五入到整数分),用 Math.round() 或 BigDecimal 控制
理解并接受 double 的适用边界
double 适合科学计算、图形渲染、机器学习等对绝对精度要求不高、但需要大范围和高速度的场景。它的误差通常在 1e-15 量级,只要不累积大量运算或不做等值判断,影响可控。
- 避免链式浮点运算后直接判 ==
- 避免用 double 作循环索引(如 for (double d = 0.0; d != 1.0; d += 0.1))—— 改用 int 计数再换算
- 日志或展示时用 String.format("%.2f", d) 或 DecimalFormat 控制输出精度,不改变数值本身
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











