应使用误差容忍法而非==比较浮点数,推荐abs(a-b)

直接用 == 判断两个浮点数是否相等,几乎必然出错。这不是 PHP、Java 或 C++ 某个语言的 bug,而是所有遵循 IEEE 754 标准的语言共有的底层限制:0.1 在二进制中无法精确表示,所以 0.1 + 0.2 算出来是 0.30000000000000004,和 0.3 的内存值不一致,== 自然返回 false。
用误差容忍法替代 == 判断
核心思路是:不追求“完全相等”,而判断“差得够不够小”。最常用且有效的做法是引入一个极小阈值(epsilon),比较两数之差的绝对值是否小于它。
-
推荐写法(通用):
abs(a - b) (double 类型)或 <code>abs(a - b) (float 类型) - 更稳妥写法(兼顾大小数值): 同时检查绝对误差和相对误差,避免在接近 0 或极大数时失效
-
注意: 不要直接用
DBL_EPSILON或Float.MIN_VALUE,它们代表的是 1.0 附近的最小可分辨增量,通常太小,不适合作为通用 epsilon
针对金融/金额类场景,改用高精度定点数
当业务逻辑对精度零容忍(比如账户余额、支付扣款),浮点类型本身就不该出现。此时应彻底避开 float/double。
-
Java 中首选
BigDecimal:务必用字符串构造,如new BigDecimal("19.99"),避免new BigDecimal(19.99)先失真再封装 -
PHP 中可用 BCMath 扩展:如
bcscale(2); $sum = bcadd('19.99', '5.01');,确保全程十进制运算 -
C/C++ 可用整数单位替代:金额统一存为“分”,全部用
int运算,输出时再除以 100
避免在循环条件或数组索引中依赖浮点值
用 for (double x = 0.0; x != 1.0; x += 0.1) 这类写法极易陷入死循环——因为 x 永远达不到精确的 1.0。
-
正确做法是用整数计数器:如
for (int i = 0; i -
条件判断慎用 == 或 !=:优先改用
、<code>>=等有序比较,浮点数的大小关系仍是可靠的 -
数据库字段设计也需同步规避:金额字段用
DECIMAL而非FLOAT或DOUBLE
调试时别被格式化输出误导
printf("%.2f", 0.1+0.2) 显示 0.30,不代表内部值就是 0.3;number_format(0.29999999999999999, 2) 也可能四舍五入成 "0.30"。显示正常 ≠ 存储精确。
-
调试建议打印原始值:如 C 中用
%.17g,Java 中用String.format("%.17g", x),看清真实位数 -
比对前先统一处理方式:如果数据库查出的是
double,PHP 计算也应走 BCMath 或转成相同精度的字符串再比

















