php大整数运算必须使用bcmath或gmp扩展,因int有平台限制、float会丢失精度;bcmath纯字符串运算、精度可控但功能有限,gmp性能更好但需安装且返回对象;数据进出各环节(输入、中间处理、json输出)均需严防精度丢失。

PHP 大整数不是靠 int 或 float 解决的
PHP 的 int 有平台限制(32 位系统最大约 21 亿,64 位约 9.2×10¹⁸),float 会丢失精度——比如 9223372036854775807 + 1 可能变成 9223372036854776000。这不是四舍五入,是二进制浮点表示的固有缺陷。
真正能保精度的大整数运算,必须用 BCMath 或 GMP 扩展。没启用这些扩展时,任何“大数”操作都不可信。
-
BCMath是 PHP 内置扩展(大多数环境默认开启),纯字符串运算,不依赖 CPU 整数类型,精度可控,但只支持四则和比较 -
GMP性能更好、功能更全(模幂、素数检测等),但需要额外安装,且返回的是资源或GMP对象,不能直接 echo - 别用
float强转或strval()拼接来“假装”处理大数——结果可能在测试时碰巧对,上线后因输入变化突然出错
用 bcadd() 做加法:参数顺序和小数位是关键
bcadd() 是最常用的大数函数,但它不像普通加法那样直觉:第三个参数 scale 控制小数位数,不是可选的“默认值”,而是强制生效的精度截断规则。
比如两个整数相加却传了 2,结果会补零;传了 0,小数部分直接被砍掉(不是四舍五入):
立即学习“PHP免费学习笔记(深入)”;
bcadd('123.456', '789.123', 2); // 返回 '912.57'
bcadd('123.456', '789.123', 0); // 返回 '912'
- 所有参数必须是字符串,传
int或float会导致隐式转换,精度已失 -
scale为 0 时,等效于向下取整(truncation),不是round() - 如果参与计算的字符串含空格或非法字符(如
' 123 '),bcadd()会静默失败,返回空字符串或错误结果
gmp_add() 快但要注意类型和输出
gmp_add() 返回的是 GMP 资源(PHP 8.0+ 是 GMP 对象),不能直接用于字符串拼接或 JSON 输出。常见错误是写 echo gmp_add('123', '456'),看起来有输出,其实是对象 toString 的默认行为,一旦涉及格式化就崩。
- 必须用
gmp_strval()转成字符串才能安全使用:gmp_strval(gmp_add('123', '456')) -
gmp_init()支持进制参数,比如gmp_init('FF', 16)可以直接解析十六进制字符串 - 如果传入非数字字符串(如
'abc'),gmp_add()不报错,而是当作0处理,极易埋下逻辑漏洞
别在 JSON 中直接输出大整数
PHP 的 json_encode() 会把大整数当 float 处理,尤其在 JavaScript 端解析时,超过 Number.MAX_SAFE_INTEGER(9007199254740991)就会丢精度。即使你用 GMP 算得再准,JSON 一序列化就废。
- 方案一:始终用字符串传输,服务端用
gmp_strval()或strval()(仅当确定是 BCMath 结果)包裹后再json_encode() - 方案二:前端用
BigInt或字符串接收,明确约定该字段永不转数字 - 别依赖
JSON_BIGINT_AS_STRING(PHP 5.4+ 的json_encode()选项)——它只对原始int字段生效,对 GMP/BCMath 计算结果无效
大整数的坑不在计算本身,而在数据进出的每个环节:输入是否干净、中间是否误转、输出是否被 JSON 或数据库字段类型截断。漏掉任何一环,前面所有高精度计算都白做。











