首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 浮點數比較陷阱深度解析:FLOAT/DOUBLE 精度缺失、DECIMAL 精確替代與測試驗證

     編輯:MySQL 資料庫相關知識

核心現象

CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00), ...;
SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1 GROUP BY i HAVING a <> b;
-- 返回 6 行,肉眼看 a=b 卻判定不相等

根本原因:IEEE 754 二進制浮點表示

  • 十進制小數 (0.1, 0.2, 0.3...) 在二進制中為無限循環小數,無法精確表示。
  • FLOAT (4 位元組、~7 位有效數字)、DOUBLE (8 位元組、~15 位) 均為近似值。
  • 螢幕顯示為四捨五入後的人類可讀形式,實際儲存值含微小誤差。

DECIMAL 精確數值型別

  • 以字串形式儲存,逐位十進制編碼 (BCD 或類似),無精度損失。
  • DECIMAL(10,2) 精確表示 99999999.99 至 -99999999.99。
  • 運算精度:MySQL 64 位十進制運算,足覆蓋絕多數商業場景。

實測對比

型別同樣資料查詢 HAVING a <> b說明
DOUBLE返回 6 行 (含誤差行)累加誤差放大導致判定不等
DECIMAL僅返回 1 行 (真正不等行)精確運算,無誤差干擾

正確比較策略

  1. 金額/精度敏感欄位:強制使用 DECIMAL,定義精度 (M,D) 滿足業務上限。
  2. 科學計算/近似容許:使用 DOUBLE,比較時採用容差範圍:
    WHERE ABS(float_col - target) < 0.0001
  3. 避免直接等值比較:WHERE float_col = 1.23 ❌ → WHERE float_col BETWEEN 1.2299 AND 1.2301 ✅

應用層最佳實踐

  • 資料庫層:price DECIMAL(10,2) NOT NULL、rate DECIMAL(5,4)。
  • ORM/程式碼:使用 BigDecimal (Java)、decimal.Decimal (Python)、decimal (C#),禁止 float/double 處理金額。
  • 匯入/匯出:CSV/JSON 中數值以字串輸出 "123.45",避免解析端浮點化。

結語

浮點數比較問題是計算機科學基礎知識缺失導致的經典坑。鐵律:錢用 DECIMAL、科學計算用 DOUBLE+容差、永不直接 == 比較浮點數。資料庫設計評審時,凡涉及金額、比率、庫存計量 必須檢查型別為 DECIMAL。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved