PHP中相似数组求和结果为何出现判断差异?
PHP浮点数求和的精度问题(Laravel 8 + PHP 8环境)
在Laravel 8、PHP 8环境下开发时遇到一个特殊情况:两个数组仅元素顺序和微小数值不同,理论上求和结果都应该是100。用array_sum计算后,dump显示两者结果都是100.0,但条件判断时,其中一个数组的求和结果能判定等于100和100.0,另一个却判定不等。原本以为这和PHP_FLOAT_EPSILON无关,实际恰恰是浮点数精度导致的问题。
相关代码如下:
$c = [ 23.3, 33.4, 43.3, ]; $d = [ 43.3, 23.4, 33.3, ]; $ccc = array_sum($c); $ddd = array_sum($d); dump($ccc); // output: 100.0 dump($ddd); // output: 100.0 if ($ccc != 100) { dump('$ccc is not equal to 100'); } else { dump('$ccc is equal to 100'); // 实际输出这行 } if ($ccc != 100.0) { dump('$ccc is not equal to 100.0'); } else { dump('$ccc is equal to 100.0'); // 实际输出这行 } if ($ddd != 100) { dump('$ddd is not equal to 100'); // 实际输出这行 } else { dump('$ddd is equal to 100'); } if ($ddd != 100.0) { dump('$ddd is not equal to 100.0'); // 实际输出这行 } else { dump('$ddd is equal to 100.0'); }
问题原因
本质是浮点数的二进制存储精度限制:像23.3、33.4这类十进制小数,无法被精确转换成二进制浮点数,存储时本身就带有微小误差。当不同顺序的浮点数累加时,这些误差会被累积放大,最终导致$ddd的实际值和100.0存在极小的差异(比如可能是100.00000000000003或者99.99999999999997),而dump输出时做了四舍五入显示,所以看起来都是100.0,但实际比较时就能测出差异。
解决方案
- 使用高精度数学扩展:比如PHP的bcmath扩展,通过精确的十进制计算避免浮点数误差,示例代码:
function bc_array_sum($array, $scale = 2) { $sum = '0'; foreach ($array as $num) { $sum = bcadd($sum, (string)$num, $scale); } return $sum; } $ccc = bc_array_sum($c); $ddd = bc_array_sum($d); // 此时比较字符串形式的数值即可 if ($ddd == '100.00') { // 相等逻辑 }
- 允许误差范围的比较:如果必须使用浮点数,比较时用
PHP_FLOAT_EPSILON判断差值是否在可接受的精度范围内:
if (abs($ddd - 100.0) < PHP_FLOAT_EPSILON) { dump('$ddd is equal to 100.0'); } else { dump('$ddd is not equal to 100.0'); }
内容的提问来源于stack exchange,提问作者enaeim
相关产品推荐
相关产品推荐

