decimal是唯一能真正规避精度丢失的方案,因其以字符串解析、整数运算、缩放还原的方式全程避开ieee 754二进制存储与计算,确保0.1等十进制小数精确存储与运算,而float/double从插入起即因二进制无限循环导致存储失真,后续计算误差持续累积。

DECIMAL 是唯一能真正规避精度丢失的方案,因为 FLOAT 和 DOUBLE 从存入那一刻起就不是你写的那个数——比如插入 0.1,查出来是 0.10000000149011611938,这不是计算错,是存储即失真。
浮点数根本存不准 0.1 这类十进制小数
计算机用二进制存数字,而 0.1 在二进制里是无限循环小数(类似十进制的 1/3 = 0.333...),必须截断。IEEE 754 标准下,FLOAT 最多保留约 7 位有效十进制数字,DOUBLE 约 15–17 位,超出部分直接丢弃或四舍五入。
-
INSERT INTO t(v) VALUES(0.1);存进去的已经是近似值,不是0.1 - 后续所有计算都基于这个“假 0.1”进行,误差只会累积,不会消失
- 哪怕只做一次
SELECT 0.1 + 0.2,结果也是0.30000000000000004,不是显示问题,是真实计算值
运算过程会隐式转类型,链路一断全漂移
MySQL 对类型推导很宽松,常量、函数、字段混合运算时极易触发隐式转换,中间结果悄悄变成 DOUBLE,精度立刻失控。
-
SELECT 100 / 3;返回DOUBLE,不是你想的“除不尽但精确” -
SELECT CAST(100 AS DECIMAL(10,2)) / CAST(3 AS DECIMAL(10,2));才返回DECIMAL类型的33.33333333333333 - 存储过程中声明
DECLARE x DECIMAL;直接报错;漏写(M,D)就没法用 - 调用函数传
100和100.0效果完全不同:前者被当INT→ 参与运算时可能升为DOUBLE,后者明确提示要走十进制路径
DECIMAL 不是“更高精度的浮点”,而是换了一套算术逻辑
DECIMAL(M,D) 本质是把数字当字符串解析、按整数做运算、再按小数点缩放,全程避开二进制表示和 IEEE 754 规则。
-
DECIMAL(15,2)能存-9999999999999.99到9999999999999.99,每个值都严格可预期 - 两个
DECIMAL(10,2)相加,结果是DECIMAL(11,2);相乘是DECIMAL(20,4)—— 类型推导有规则,但必须显式对齐 - 如果中间结果赋给一个窄的变量(如
DECIMAL(10,2)),超长部分会静默四舍五入,不报错也不警告
CAST 或没传带小数点的字面量(如 100.0),整个计算链就掉回浮点陷阱——MySQL 不提醒,应用层也难察觉,直到账对不上。











