浮點數精度問題並非 MySQL 獨有,而是 IEEE 754 標準 導致的必然結果。單精度 FLOAT(32 位:1 符號位 + 8 指數位 + 23 尾數位)有效十進制數字約 **7-8 位**,超出即產生誤差;雙精度 DOUBLE(64 位)約 **15-16 位**。
CREATE TABLE t (num FLOAT(9,3));
INSERT INTO t VALUES (123456.8);
SELECT * FROM t; -- 顯示 123456.797(非 123456.800)
原因:123456.8 二進制尾數超過 23 位,捨入導致誤差。
INSERT INTO t VALUES (2.8);
SELECT * FROM t WHERE num = 2.8; -- 無結果!
-- 實際儲存值為 2.8000000715... 需用範圍查詢
SELECT * FROM t WHERE num BETWEEN 2.799 AND 2.801;
| 分類 | 型別 | 儲存 | 精度 | 適用場景 |
|---|---|---|---|---|
| IEEE 754 浮點數 | FLOAT | 4 bytes | ~7 位 | 科學計算、非精確測量 |
| DOUBLE / REAL | 8 bytes | ~15 位 | 較大範圍非精確計算 | |
| 定點數(精確) | DECIMAL / NUMERIC | 可變 | 自定精確度 | 貨幣、金融、庫存、精確測量 |
// Java 範例
System.out.println(7.22f - 7.0f); // 輸出 0.21999979 而非 0.22
浮點數比較嚴禁使用 ==/!=,應用 Math.abs(a-b) < epsilon 容差比較。
DECIMAL(p,s):貨幣、價格、數量等精敏欄位FLOAT:明確指定精度 FLOAT(10,2),查詢用 FORMAT(col,2) = FORMAT(val,2)(精度 ≤ 6)WHERE 直接比較浮點欄位,改用範圍 BETWEEN 或整數化存儲(如分為單位存 INT)DECIMAL 是精確計算唯一正解NaN、Infinity、+0/-0 等特殊值處理