Laravel环境下PHP浮点数值比较if条件判断异常问题求助
问题根因
这是浮点数二进制存储的固有精度误差导致的,属于所有采用IEEE 754标准存储浮点数的编程语言的通用特性:
- 你业务中用到的
33.98、9.8这类十进制小数,转换成二进制时属于无限循环小数,计算机存储时会做截断近似,本身就存在极微小的误差 - 两个比较变量都是经过多次累加得到的,累加过程中误差会累计,最终两个值的二进制尾数可能存在肉眼不可见的极小差异
- 直接用
echo输出时,PHP默认只会展示浮点数小数点后2位/前14位有效数字,会把这个极小的差异隐藏;你可以用printf("%.20f\n%.20f", $totalEcheances, $totalEcriture)打印20位小数,就能直观看到两者的实际差值 !==是严格全等比较,会对比两个浮点数的全部二进制位,只要尾数有1位差异就会判定为不相等- 你用到的
mb_ord调试逻辑没有参考价值,它返回的是变量转字符串后第一个字符的Unicode编码,和数值本身的存储精度无关
修复方案
方案1:设置误差阈值(epsilon)比较
不要直接做全等判断,而是判断两个值的差的绝对值是否小于业务可接受的最小误差,针对金额类业务一般取0.0001即可:
// 小于1分钱的差异视为相等 $epsilon = 0.0001; if (abs(floatval($totalEcheances) - floatval($totalEcriture)) > $epsilon) { // 原有判定为不等的处理逻辑 }
方案2:转整数比较(更适合金额场景)
因为你的数值都是两位小数的金额,可以统一转成以「分」为单位的整数再比较,完全避免浮点数误差:
$totalEcheancesInt = (int)round(floatval($totalEcheances) * 100); $totalEcritureInt = (int)round(floatval($totalEcriture) * 100); if ($totalEcheancesInt !== $totalEcritureInt) { // 原有判定为不等的处理逻辑 }
内容的提问来源于stack exchange,提问作者Bill Ballois
相关产品推荐
相关产品推荐

