← 返回首页

PHP 浮点数精度问题是什么?如何用 bcmath 解决?

PHP 浮点数精度问题

PHP 遵循 IEEE 754 标准,浮点数用二进制存储,无法精确表示某些十进制小数,导致计算结果出现偏差:

var_dump(0.1 + 0.2 == 0.3);          // false
var_dump(0.1 + 0.2);                  // float(0.30000000000000004)

var_dump(0.3 - 0.2 == 0.1); // false
var_dump(0.3 - 0.2); // float(0.09999999999999998)

常见受影响场景:金额计算、价格比较、库存扣减等对精度要求高的业务。


用 bcmath 解决

bcmath 支持任意精度的数学运算,数字以字符串形式参与计算,不会丢失精度。

基本用法

// 加法
bcadd('0.1', '0.2', 2);       // "0.30"

// 减法
bcsub('0.3', '0.2', 2); // "0.10"

// 乘法
bcmul('0.1', '0.2', 4); // "0.0200"

// 除法
bcdiv('1', '3', 6); // "0.333333"

// 比较(返回 0 表示相等)
bccomp('0.3', bcadd('0.1', '0.2', 2), 2); // 0(相等)

// 取余
bcmod('10', '3'); // "1"

// 幂运算
bcpow('2', '10'); // "1024"

参数说明

  • 前两个参数:操作数(必须传字符串)
  • 第三个参数:小数位数(精度),不传则使用默认值

设置全局精度

// 设置默认小数位数为 4
bcscale(4);

bcdiv('1', '3'); // "0.3333"(无需每次传精度)


实际应用场景:金额计算

// 错误做法
$total = 0.1 + 0.2;  // 0.30000000000000004

// 正确做法
$total = bcadd('0.1', '0.2', 2); // "0.30"

// 金额比较
if (bccomp($price, '0.00', 2) > 0) {
echo '价格大于0';
}


其他解决方式对比

方式 适用场景 示例
bcmath 高精度计算(推荐) bcadd('0.1', '0.2', 2)
转为整数计算 金额(分) (10 + 20) / 100
round() 简单展示 round(0.1 + 0.2, 2)
number_format() 格式化输出 number_format(0.1+0.2, 2)

总结:涉及金额、财务等精确计算时,务必用 bcmath 并以字符串传参。round() 只是"看起来对了",底层精度问题依然存在,不适合做逻辑判断。