PHP json_encode浮点数精度偏差源于IEEE 754限制及serialize_precision配置,默认输出冗余小数;推荐设serialize_precision=-1、浮点字段主动转字符串、递归预处理数组或源头避免浮点运算。

PHP 的 json_encode 在处理浮点数时出现精度偏差(比如 0.1 变成 0.10000000000000001),根本原因是 IEEE 754 双精度浮点数无法精确表示大部分十进制小数,而 PHP 默认序列化精度设置(serialize_precision)又放大了这一现象。解决的关键不是“修复浮点数”,而是**控制输出表现形式**,确保业务需要的精度不被破坏。
统一调整 serialize_precision 配置
这是最彻底、影响全局的方式,适用于项目可控、能修改运行环境的场景:
- PHP 7.1+ 推荐设为 -1:启用自动最优精度模式,底层调用
dtoa算法,能准确还原原始值(如0.1输出为0.1,而非长串近似值) - 若不能改 php.ini,可在脚本开头临时设置:
ini_set('serialize_precision', -1); - 注意:设为
14或16也能缓解,但-1是官方推荐解,自 PHP 7.1.0 起生效且更可靠
对浮点字段主动转字符串
适合金融、地理坐标等对显示格式敏感的字段,简单直接、零兼容风险:
- 在组装数组时就转:
$data = ['price' => (string)29.99, 'lat' => (string)31.219319]; - 或用
number_format控制位数再转:'price' => number_format(29.99, 2, '.', '')→ 输出"29.99",且无尾随零 - 优点是完全绕过浮点序列化环节,前端拿到的就是纯字符串,解析后也不会再计算
递归预处理数组中的浮点数
适合已有复杂嵌套结构、不想逐个字段手动处理的场景:
立即学习“PHP免费学习笔记(深入)”;
- 写一个通用函数,遍历所有值,对
is_float()的项做number_format或强转字符串 - 示例逻辑:
function fix_floats($data, $precision = 2) {<br> if (is_float($data)) {<br> return number_format($data, $precision, '.', '');<br> }<br> if (is_array($data)) {<br> return array_map(function($v) use ($precision) { return fix_floats($v, $precision); }, $data);<br> }<br> return $data;<br>} - 调用:
json_encode(fix_floats($original_data))
避免在 JSON 中依赖浮点运算结果
从源头减少问题发生:
- 金额类数据,数据库存整数分、前端/后端统一按分计算,避免
0.1 + 0.2类运算 - 读取外部 JSON 时,如果原始字段是字符串形式的数字(如
"9.99"),不要用(float)强转,保留字符串或用bcadd/bcmul做高精度计算 - 地理坐标等需高精度展示的,可约定接口返回字符串,或明确要求保留固定小数位(如 6 位)



















