萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL FLOAT vs DECIMAL 精度大比拚:財務金額務必用 DECIMAL

核心差異一覽

特性FLOAT / DOUBLEDECIMAL / NUMERIC
儲存方式二進制浮點數(IEEE 754)定點數,以字串形式逐位儲存
精度近似值,有捨入誤差精確值,無捨入誤差
適用場景科學計算、測量數據、圖形座標貨幣、金融、庫存計量、精確比對
空間FLOAT 4B、DOUBLE 8BDECIMAL(M,D) 約 M+2 字節
比較運算避免 = / <>,用範圍比較可直接用 = / <> / BETWEEN

實測誤差演示

CREATE TABLE t1 (c1 FLOAT(10,2), c3 DECIMAL(10,2));
INSERT INTO t1 VALUES (1234567.23, 1234567.23), (9876543.21, 9876543.12);
SELECT * FROM t1;
+------------+------------+
| c1         | c3         |
+------------+------------+
| 1234567.25 | 1234567.23 |  -- FLOAT 產生誤差
| 9876543.00 | 9876543.12 |  -- FLOAT 精度丟失
+------------+------------+

FLOAT(10,2) 非標準語法(M=總位數,D=小數位),實際精度受硬體影響。DECIMAL 精確保留輸入值。

負數與邊界測試

INSERT INTO t1 VALUES (-98765430.21, -98765430.12);
SELECT * FROM t1;
+--------------+--------------+
| c1           | c3           |
+--------------+--------------+
| -98765432.00 | -98765430.12 |  -- FLOAT 再次失真
+--------------+--------------+

符號位不佔精度位,但浮點誤差依然存在。

DECIMAL 精度上限

  • MySQL 5.0+:DECIMAL(65,30) 最大精度 65 位,標度 30 位。
  • 儲存空間:整數部每 9 位 4 字節,小數部每 9 位 4 字節。
  • 可精確表示 ±10^65 範圍內任意定點數。

開發鐵律

  1. 金額、價格、匯率、利率、庫存計量 → 只用 DECIMAL。
  2. WHERE 條件:禁用 WHERE float_col = 1.23,改用 WHERE float_col BETWEEN 1.229 AND 1.231 或改欄位為 DECIMAL。
  3. 程式語言端:Java 用 BigDecimal、Python 用 decimal.Decimal、Go 用 shopspring/decimal,嚴禁 float64 運算金額。
  4. 遷移建議:現有 FLOAT 金額欄位,建立 DECIMAL 新欄位 → 回填資料 → 雙寫驗證 → 切換流量 → 刪舊欄位。

原理補充

MySQL decimal_t 結構體以 decimal_digit_t 陣列(基數 10000)儲存,intg/frac 分別記錄整數/小數位數,sign 標記正負,運算皆為十進制模擬,故無二進制轉換誤差。

copyright © 萬盛學電腦網 all rights reserved