FLOAT类型本质是二进制近似存储,0.1在二进制中为无限循环小数,23位尾数截断后存为≈0.10000000149011612,导致0.1+0.2=0.30000000000000004等误差,且不可用于等值比较。

FLOAT 类型本质是二进制近似存储,不是十进制精确表示
0.1 在二进制里是无限循环小数(类似十进制中 1/3 = 0.333…),而 FLOAT 只有 23 位尾数(单精度),必须截断或舍入,导致存进去的就不是真正的 0.1,而是 0.10000000149011612 这类近似值。后续所有加减乘除都在这个“不准的起点”上运算,误差自然累积。
为什么 SELECT 0.1 + 0.2 返回 0.30000000000000004?
这不是 MySQL 特有 bug,而是 IEEE 754 单精度浮点规则在起作用:
-
0.1和0.2分别被转成最接近的FLOAT表示,各自已有微小误差 - 两者的二进制近似值相加后,结果仍需四舍五入到 23 位尾数精度
- 最终显示的
0.30000000000000004是该二进制和转回十进制时的“忠实还原”,不是计算错误
为什么用 WHERE num = 0.12 查不到 FLOAT 字段?
这是精度丢失最常踩的坑:浮点数不能安全用于等值比较。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 建表时只写
num FLOAT,MySQL 实际按隐式精度处理,插入0.12后存的是近似值 - 查询时写
WHERE num = 0.12,MySQL 把字面量0.12也转成FLOAT近似值,但两次转换路径可能不完全一致 - 更稳妥的做法是用范围比较:
WHERE num BETWEEN 0.119 AND 0.121,或直接改用DECIMAL
DECIMAL(10,2) 真的就能避免所有问题?
能,但前提是全程用对——很多人忽略中间环节的隐式类型转换。
- 如果字段是
DECIMAL(10,2),但写SELECT value + 0.1 FROM t,MySQL 会把0.1当作DOUBLE处理,整个表达式升格为DOUBLE,结果又变浮点 - 正确写法是显式转类型:
SELECT value + CAST(0.1 AS DECIMAL(10,2)) FROM t - 或者统一用字符串字面量:
SELECT value + 0.10 FROM t(末尾补零有助于 MySQL 推断为定点数)
真正容易被忽略的点是:精度问题不只出在存储层,更藏在计算链路的每一步类型推导里。哪怕字段定义再严谨,一个没加 CAST 的字面量、一次没注意的函数返回类型(比如 SUM() 对 FLOAT 列返回 DOUBLE),都可能让 DECIMAL 的防线瞬间失效。










