java浮点数基于ieee 754标准,无法精确表示0.1、0.2等十进制小数,导致0.1+0.2≠0.3;应使用误差容忍范围(如1e-10)配合math.abs(a-b)比较。

Java 中的浮点数(float 和 double)基于 IEEE 754 标准,无法精确表示大多数十进制小数(如 0.1、0.2),因此算术运算符(+、-、*、/、%)在计算时会累积舍入误差。这不是 Java 的 Bug,而是二进制浮点表示的固有局限。
为什么 0.1 + 0.2 != 0.3?
因为 0.1 和 0.2 在二进制中是无限循环小数,必须被截断存储。例如:
double a = 0.1 + 0.2;System.out.println(a == 0.3); // 输出 falseSystem.out.println(a); // 输出 0.30000000000000004
加法运算本身没错,但输入值已失真,结果自然偏差。
避免直接用 == 比较浮点数
应使用「误差容忍范围」(epsilon)判断是否“足够接近”:
- 定义一个极小阈值,如
1e-10(适用于double)或1e-6(适用于float) - 用
Math.abs(a - b) 替代 <code>a == b - 注意:epsilon 大小需匹配数值量级;对极大数(如
1e20)需用相对误差,如Math.abs(a - b)
需要精确计算时,改用 BigDecimal
金融、计费等场景严禁误差,应避免 float/double:
- 构造
BigDecimal时优先用字符串(new BigDecimal("0.1")),而非double字面量(new BigDecimal(0.1)仍会带入原始误差) - 指定舍入模式(如
RoundingMode.HALF_UP)和精度,尤其在除法(divide())中必须显式声明 - 注意性能开销较大,不适用于高频科学计算或实时系统
简单场景可考虑整数缩放(如金额用“分”代替“元”)
将小数转为整数运算,彻底规避浮点误差:
- 价格
19.99元 → 存为1999(单位:分) - 所有加减乘除均用
int或long进行,仅在展示时除以100.0 - 适合规则明确、小数位数固定的业务(如货币、百分比)
理解浮点数的表示本质,比“修复”运算符更重要。选对工具——比较用 epsilon、精度要求高用 BigDecimal、规则简单用整数缩放——才能真正应对误差问题。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











