因为float用ieee 754二进制表示,0.1等十进制小数无法精确存储,只能近似,导致计算如0.1+0.2=0.30000000000000004;而decimal按十进制定点存储,全程无二进制舍入,保证精度。

为什么MySQL中浮点数FLOAT计算会出现精度丢失
因为FLOAT底层用的是IEEE 754二进制浮点表示,而大多数十进制小数(如0.1、0.2)无法被精确表示为有限位二进制小数——它只能被近似存储,后续所有计算都基于这个近似值展开。
FLOAT和DECIMAL在存储机制上的根本差异
FLOAT存的是“近似值”:0.1实际存成0.10000000149011611938;DECIMAL(10,2)存的是“字符串级精确值”,按十进制逐位编码,不经过二进制转换。
-
FLOAT:4字节(单精度),尾数23位 → 十进制有效数字约6~7位 -
DOUBLE:8字节(双精度),尾数52位 → 十进制有效数字约15~16位 -
DECIMAL(M,D):按字符/定点方式存储,M位总长、D位小数,全程无二进制舍入
哪些操作会让FLOAT精度问题突然暴露
不是所有查询都会立刻显形,但以下场景极易触发可见误差:
- 相加后比较:
SELECT 0.1 + 0.2 = 0.3;返回0(实际值是0.30000000000000004) - 聚合计算:
SUM()对FLOAT列累加,误差会累积放大 - WHERE条件中用浮点等值判断:
WHERE price = 9.99可能查不到刚插入的9.99 - 与整数混合运算:
100 * 0.08中0.08被当DOUBLE解析,结果类型漂移
为什么改用DECIMAL还不够——函数内仍可能掉坑
即使表字段是DECIMAL,只要在存储过程或函数里用了FLOAT变量、漏写标度、或调用时传裸数字,精度链就断了:
-
DECLARE total DECIMAL;❌ 报错,MySQL要求必须带(M,D) -
DECLARE rate DECIMAL(12,6);✅ 正确,但若CALL calc(0.08);传参,0.08仍被当DOUBLE解析 -
SET @x = 100 / 3;❌ 结果是DOUBLE,约33.333333333333336 -
SET @x = CAST(100 AS DECIMAL(10,2)) / CAST(3 AS DECIMAL(10,2));✅ 全链路保DECIMAL
真正危险的是静默失效:MySQL不报错、不警告,只给你一个“看起来对”的错值——比如金额多出0.00000001元,批量结算时差几毛钱,却查不出源头。











