PHP中比较两个double变量时出现异常问题
PHP中浮点数比较结果不符合预期的原因与解决方法
问题代码
$pra = $this->PercentualeRicaricoApplicata; // 注释显示为37 $current = floatval($currentPercentage->RicaricoPercentuale); // 注释显示为37 $lower = floatval($lowerPercentage->RicaricoPercentuale); // 注释显示为27 myecho(gettype($pra) . ' - ' .gettype($current) . ' - ' . gettype($lower)); echo '<br>pra <= current: ';var_dump($pra <= $current); echo '<br>pra >= current: ';var_dump($pra >= $current); echo '<br>current >= pra: ';var_dump($current >= $pra); echo '<br>pra <= current: ';var_dump(37.00 <= 37.00); echo '<br>pra > lower: ';var_dump($pra > $lower);
执行结果
double - double - double pra <= current: bool(false) pra >= current: bool(true) current >= pra: bool(false) pra <= current: bool(true) pra > lower: bool(true)
原因分析
这是典型的浮点数精度问题:
- 虽然注释标注两个变量值都是37,但浮点数在二进制存储时,部分十进制数值无法被精确表示,会以近似值存储。
$pra和$current实际存储的二进制浮点数可能存在极其微小的差异(比如一个是37.000000000000004,另一个是37.0),导致直接比较时出现不符合直觉的结果。 - 直接写
37.00 <= 37.00时,PHP会将两个字面量解析为同一个浮点数实例,所以比较结果为true。
解决方法
阈值比较法
不要直接对浮点数进行相等/大小比较,而是判断两个数的差值绝对值是否小于一个极小的阈值(比如1e-9,可根据精度需求调整):$epsilon = 1e-9; // 判断 $pra <= $current var_dump(abs($pra - $current) <= $epsilon || $pra < $current); // 判断 $current >= $pra var_dump(abs($current - $pra) <= $epsilon || $current > $pra);整数存储精确数值
如果是百分比、货币这类需要精确计算的场景,建议将数值转换为整数存储(比如把37%存储为37,带小数的37.5%存储为375,计算时再除以10),从根源避免浮点数精度问题。高精度数学扩展
使用PHP的bcmath扩展进行高精度数值比较,该扩展支持任意精度的十进制运算:// 先将浮点数转为字符串,避免精度丢失 var_dump(bccomp((string)$pra, (string)$current) <= 0); // 等价于 $pra <= $current var_dump(bccomp((string)$current, (string)$pra) >= 0); // 等价于 $current >= $pra
内容的提问来源于stack exchange,提问作者Fabrizio La Racca
相关产品推荐
相关产品推荐

