You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP中双精度数值相等但比较返回FALSE问题问询

为什么MySQL的double与decimal求和结果在PHP中比较不相等?

核心问题解析

你遇到的问题本质是二进制浮点数的精度误差,以及MySQL不同数值类型在PHP中的处理逻辑差异导致的:

  • 从double(7,3)字段求和得到的$totalPrice,PHP解析为float类型后,实际值是39.669000000000004(而非表面显示的39.669)
  • 从decimal(20,3)字段求和得到的$totalFinalPrice,PHP默认以字符串返回精确值"39.669",强制转float后得到的近似值和前者的微小误差,直接导致比较失败

原因拆解

  1. MySQL字段类型的本质区别

    • double是二进制浮点型:存储的是十进制数的二进制近似值,即使定义了(7,3)的精度,底层仍会存在微小误差,求和操作会放大这种误差
    • decimal是精确数值类型:以字符串形式存储十进制数,求和后返回的是精确的十进制字符串,不会产生浮点误差
  2. PHP的类型转换逻辑

    • 读取MySQL的double结果时,PHP直接将二进制浮点值映射为自身的float/double类型,保留了底层的精度误差
    • 读取MySQL的decimal结果时,PHP默认以字符串返回(避免精度丢失),当强制转为float时,PHP会将字符串"39.669"解析为最接近的二进制浮点值,但这个值和double字段求和后得到的浮点值并非完全一致

验证精度差异的方法

用高精度格式化输出就能看到真实值:

// 查看$totalPrice的真实精度
var_dump(sprintf('%.20f', $totalPrice)); // 输出 39.66900000000000400000

// 查看强制转float后的$totalFinalPrice真实精度
var_dump(sprintf('%.20f', (float)$totalFinalPrice)); // 输出 39.66899999999999700000(或近似的精确表示)

正确的比较方式

  1. 直接用字符串比较:如果$totalFinalPrice是decimal返回的字符串,将$totalPrice格式化后再比较:
if (sprintf('%.3f', $totalPrice) === $totalFinalPrice) {
    // 相等逻辑
}
  1. 使用高精度函数比较:用PHP的BCMath扩展处理精确数值比较:
// 保留3位小数进行比较
if (bccomp((string)$totalPrice, $totalFinalPrice, 3) === 0) {
    // 相等逻辑
}
  1. 在MySQL层面统一类型:查询时将double的求和结果转为decimal,避免PHP端的精度问题:
SELECT CAST(SUM(price) AS DECIMAL(20,3)) AS total_price FROM Packs;
SELECT SUM(final_price) AS total_final_price FROM Contracts;

此时PHP读取到的两个值都是字符串类型的精确值,直接比较即可。

内容的提问来源于stack exchange,提问作者guyaloni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:22:48