<p>浮点数用==判断相等易致逻辑错误,因二进制无法精确表示多数十进制小数而产生舍入误差;应改用Math.abs(a - b) < epsilon进行误差容忍比较。</p>

浮点数直接用 == 判断相等,是导致分支逻辑出错、结算结果偏差的高频根源。根本原因在于:浮点数在二进制中无法精确表示多数十进制小数(如 0.1、0.2),计算过程会引入微小舍入误差,使本应“相等”的值在内存中实际不等。
识别分支中危险的 == 比较点
重点扫描业务代码中涉及金额、权重、阈值、比例等场景的 if/else 或 switch 分支条件:
- 检查所有形如
if (price == 99.9)、if (rate == 0.05)、if (discount == 0.1)的判断 - 关注从数据库、JSON、HTTP 参数读取后未做类型转换或标准化就参与比较的 float/double 变量
- 留意经过加减乘除、类型转换(如 double → float)、序列化反序列化后的值,误差可能被放大或隐藏
用误差容忍(epsilon)替代严格相等
将 == 替换为「差值小于可接受误差范围」的判断,是通用且安全的做法:
- 定义合理 epsilon:金额类建议用
1e-6(百万分之一元),比例类可用1e-5或1e-4 - 写成
Math.abs(a - b) ,避免因浮点溢出或 NaN 导致异常 - 对关键路径封装工具方法,例如:
isAmountEqual(double a, double b) { return Math.abs(a - b)
优先使用定点数或整数运算
涉及金钱、积分、库存等强精度要求的场景,应从根本上规避浮点数:
- 金额统一存为「分」(long 类型),所有计算基于整数进行,展示时再除以 100.0
- 配置类比例(如 5%)存储为整数 5,运行时按需转为
5 / 100.0用于计算,但分支判断仍用整数(如if (discountPercent == 5)) - Java 可考虑
BigDecimal,但需注意构造方式——必须用字符串构造(new BigDecimal("0.1")),禁用 double 构造器(new BigDecimal(0.1)会继承原始误差)
加强测试与监控覆盖
仅靠人工排查易遗漏,需建立防御性机制:
- 在单元测试中显式构造含舍入误差的输入(如
0.1 + 0.2结果不等于0.3),验证分支是否走对 - 静态扫描接入规则:对项目中所有
float ==、double ==出现位置自动告警 - 线上关键结算链路增加日志埋点,记录参与比较的原始值、计算后值、epsilon 判断结果,便于故障回溯


















