萬盛學電腦網

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

MySQL FLOAT/DOUBLE 精度陷阱:為什麼 131072.32 變 131072.31?

經典現場

CREATE TABLE test (c1 FLOAT(10,2), c2 DECIMAL(10,2));
INSERT INTO test VALUES (131072.32, 131072.32);
SELECT * FROM test;
-- c1=131072.31  c2=131072.32  ← 浮點數誤差!

根本原因:IEEE 754 二進位表示

  • FLOAT:4 字節(32 位),單精度,有效數字 ~7 位
  • DOUBLE:8 字節(64 位),雙精度,有效數字 ~15 位
  • 許多十進位小數(如 0.1、0.22、131072.32)在二進位是無限循環,截斷即產生誤差

MySQL 數值型別對照

類型儲存精度適用場景
FLOAT4 bytes~7 位有效數字科學計算、近似值、不需精確
DOUBLE8 bytes~15 位有效數字高精度科學計算
DECIMAL(M,D)M+2 bytes精確到 D 位小數貨幣、金融、精確計算
NUMERIC同 DECIMAL同 DECIMAL同 DECIMAL

MySQL 非標準語法

FLOAT(M,D)     -- M 總位數,D 小數位(僅顯示寬度,儲存仍為浮點)
DOUBLE(M,D)
DECIMAL(M,D)   -- 標準,精確定點數

程式語言同樣中招

// Java
System.out.println(7.22f - 7.0f);  // 0.21999979 ≠ 0.22

// Python
print(0.1 + 0.2)  // 0.30000000000000004

規則:絕不直接比較浮點數相等,用絕對值差 < epsilon 判斷。

最佳實踐

  1. 金額、價格、費率、餘額 → DECIMAL(19,4) 或 BIGINT 存分/厘
  2. 測量、座標、科學數值 → DOUBLE
  3. 顯示層格式化:資料庫存精確值,應用層格式化輸出
  4. 避免 FLOAT(M,D):誤導以為精確,實際仍是近似

Oracle 對照

  • NUMBER(p,s):精確定點數(對應 MySQL DECIMAL)
  • BINARY_FLOAT/DOUBLE:IEEE 754 浮點數(同樣不精確)

總結

浮點數天生不精確。凡涉及錢、精確計算,唯一正解是 DECIMAL(或整數存最小單位)。程式碼中禁止 == 比較 float/double。

copyright © 萬盛學電腦網 all rights reserved