PHP浮点数精度导致while循环满足条件却无法进入问题排查
问题原因
这是典型的浮点数精度丢失问题:PHP和绝大多数编程语言的浮点数采用二进制存储规则,0.1、0.02这类十进制小数无法被二进制精确表示,多次加减操作后会产生肉眼不可见的微小误差。你通过echo看到的0.02是输出时自动四舍五入后的结果,实际存储的数值可能是0.0199999999999996这类略小于0.02的值,才会出现看起来满足>=0.02的判断条件、却没有进入对应循环的异常表现。
修复方案
方案1:转分单位整数运算(最稳妥)
将所有金额单位从元转换为分,全程用整数做计算,完全规避浮点数精度问题,修改后代码如下:
<?php function leastChange($price, $payment) { $coins = array(); // 转成分单位整数,加0.5是为了避免浮点数转整数时的截断误差 $change = (int)(($payment - $price) * 100 + 0.5); echo ($change / 100) . "<br>"; while ($change >= 50) { $change -= 50; $coins[] = "50c"; } while ($change >= 20) { $change -= 20; $coins[] = "20c"; } while ($change >= 10) { $change -= 10; $coins[] = "10c"; } while ($change >= 5) { $change -= 5; $coins[] = "5c"; } echo ($change / 100) . "<br>"; while ($change >= 2) { echo "entered 2c with " . ($change / 100) . "<br>"; $change -= 2; $coins[] = "2c"; } while ($change >= 1) { echo "entered 1c with " . ($change / 100) . " <br>"; $change -= 1; $coins[] = "1c"; } foreach ($coins as $item){ echo $item. " "; } } leastChange(1.98, 8); echo '<br>'; leastChange(1.98, 5); ?>
方案2:判断加误差容忍范围
如果不想修改原有运算逻辑,可以在所有浮点数比较的地方引入一个极小的误差容忍值(也叫epsilon),抵消精度误差的影响,比如:
- 把
$change >= 0.02修改为$change >= 0.02 - 1e-8 - 其他所有类似的浮点数比较都做相同修改即可。
内容的提问来源于stack exchange,提问作者Jake Clifford
相关产品推荐
相关产品推荐

