用FLOAT和DECIMAL分别存0.1和0.2,再把同样的误差放大到1000次累加,看金额字段为什么真实不该用浮点数。
代码CREATE TABLE money_float (amt FLOAT); INSERT INTO money_float VALUES (0.1), (0.2); CREATE TABLE money_decimal (amt DECIMAL(10,2)); INSERT INTO money_decimal VALUES (0.1), (0.2);
SELECT SUM(amt) FROM money_float; → 0.30000000447034836 ← 真实不是干净的0.3 SELECT (0.1的行) + (0.2的行) = 0.3 FROM money_float; → 0 (false,真实判断不相等) SELECT SUM(amt) FROM money_decimal; → 0.30 ← 真实精确 SELECT (0.1的行) + (0.2的行) = 0.3 FROM money_decimal; → 1 (true,真实判断相等)
FLOAT底层用的是IEEE 754二进制浮点数,0.1和0.2这类十进制小数在二进制里真实是无限循环小数,只能被截断近似存储,加起来的结果真实带着这个近似误差;DECIMAL是按十进制精确存储的定点数(真实内部按数字串+位置来存,不经过二进制浮点转换),0.1+0.2在DECIMAL的世界里就是真实精确的0.3,不多不少。
FLOAT累加1000次: SUM = 9.999999776482582 (期望10.00,真实差了约0.0000002) DECIMAL(10,2)累加1000次: SUM = 10.00 (真实精确,一分不差)
每一步都是本文上面用真实的FLOAT和DECIMAL列跑出来的原始结果。