Laravel8/PHP8下sum求和等于100却触发>100判断原因求解
问题原因
这是符合IEEE 754标准的二进制浮点数固有的精度误差问题,PHP的浮点数运算默认遵循该标准:
- 你手动计算的十进制数值总和为100,但
7.4、1.3755、10.4这类十进制小数无法被二进制浮点数精确表示,存储时本身就存在极微小的误差,累加后实际存储的数值可能是100.0000000000001这类非常接近100、但实际大于100的数值 - 直接做
> 100的比较时会触发判断条件,而dump输出时PHP默认会将这类极小误差的浮点值四舍五入为100显示,所以会出现打印结果为100、但判断100 > 100返回true的异常表现 - 强制转float类型并不能解决问题,因为精度损失在数值存储阶段就已经产生了
解决方案
你可以根据业务精度需求选择以下任意一种方案:
- 引入可接受的误差阈值(epsilon)做比较
设置一个远小于业务允许最小精度的阈值,判断总和与100的差值是否超过该阈值:
$measuresByTS->each(function ($measures) { $sum = $measures['keys']->sum('key'); $allowError = 0.00001; // 可根据业务需要调整,示例为允许万分之一的误差 if ($sum - 100 > $allowError) { dump("sum is superior to 100 : ". $sum); } });
- 放大为整数运算后比较
将所有数值放大为整数后再累加比较,完全规避浮点数精度问题,示例中你使用的数值最多保留4位小数,可放大10000倍:
$measuresByTS->each(function ($measures) { $sumInt = $measures['keys']->sum(fn($item) => (int)round($item['key'] * 10000)); if ($sumInt > 1000000) { $sum = $measures['keys']->sum('key'); dump("sum is superior to 100 : ". $sum); } });
- 使用BC Math高精度扩展运算
如果需要更高的精度控制,可以使用PHP官方的BC Math扩展做高精度运算:
$measuresByTS->each(function ($measures) { $sum = '0'; foreach ($measures['keys'] as $item) { $sum = bcadd($sum, (string)$item['key'], 4); // 4为保留的小数位数,可按需调整 } if (bccomp($sum, '100', 4) > 0) { dump("sum is superior to 100 : ". $sum); } });
内容的提问来源于stack exchange,提问作者Juliatzin
相关产品推荐
相关产品推荐

