Contents

MySQL浮點數運算,解決輸出到程式後面尾數有0的方法

在 MySQL 中進行浮點數運算時,常常會看到像 123.30000000000001123.30000 這種奇怪的尾數。這個問題源自電腦底層的數值表示方式,了解根本原因才能選擇正確的解決方案。

IEEE 754 浮點數問題

電腦使用 IEEE 754 標準以二進位儲存浮點數。某些十進位小數(例如 0.10.3)在二進位中是無限循環小數,無法精確表示,因此儲存時會有微小誤差。

1
2
3
4
5
6
-- 浮點數計算常見問題示範
SELECT 0.1 + 0.2;
-- 結果可能是 0.30000000000000004(不是 0.3)

SELECT 99.9 * 3;
-- 可能出現 299.70000000000005 等精度問題

MySQL 數值型別比較

型別 精度 儲存大小 適用場景
FLOAT 約 7 位有效數字 4 bytes 不需精確計算的數值(如感測器數值)
DOUBLE 約 15 位有效數字 8 bytes 科學計算(仍有精度誤差)
DECIMAL(M,D) 完全精確 依精度而定 金額、財務數據(必用)

結論:金錢或需要精確計算的欄位,必須使用 DECIMAL,絕對不能用 FLOATDOUBLE

使用 DECIMAL 型別

DECIMAL(M, D) 其中 M 是總位數,D 是小數位數:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-- 建立使用 DECIMAL 的資料表
CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    price DECIMAL(10, 2),   -- 最多 10 位,小數 2 位,例如 99999999.99
    tax_rate DECIMAL(5, 4)  -- 例如 0.0500 表示 5%
);

-- 插入資料
INSERT INTO products (name, price, tax_rate)
VALUES ('商品A', 1234.56, 0.0500);

-- 精確計算,不會有浮點誤差
SELECT name, price * (1 + tax_rate) AS total_price FROM products;
-- 結果:1296.2880(精確)

去除查詢結果中多餘的零

若資料庫已有 FLOAT/DOUBLE 欄位,查詢時可用以下方式消除多餘尾數:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-- 方法一:轉 CHAR 再加 0(去除尾部無效零)
SELECT 0 + CAST(90.09008700 AS CHAR);
-- 輸出:90.090087

-- 方法二:CONVERT
SELECT 0 + CONVERT('90.09008700', CHAR);
-- 輸出:90.090087

-- 方法三:FORMAT 格式化(保留指定小數位,會加千分位逗號)
SELECT FORMAT(90.09008700, 2);
-- 輸出:90.09(字串格式)

-- 方法四:ROUND 四捨五入到指定小數位
SELECT ROUND(90.09008700, 4);
-- 輸出:90.0901

在程式端的處理

Java(BigDecimal)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 避免用 double 直接運算,改用 BigDecimal
BigDecimal price = new BigDecimal("1234.56");
BigDecimal taxRate = new BigDecimal("0.05");
BigDecimal total = price.multiply(taxRate.add(BigDecimal.ONE));

// 四捨五入到小數點後 2 位
System.out.println(total.setScale(2, RoundingMode.HALF_UP));
// 輸出:1296.29

// 從資料庫取得時,用 ResultSet.getBigDecimal() 而非 getDouble()
BigDecimal value = resultSet.getBigDecimal("price");

PHP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 使用 round() 控制小數位數
 = 90.09008700;
echo round(, 2);        // 90.09

// 使用 number_format() 格式化輸出
echo number_format(, 2); // 90.09

// 需要精確計算時使用 BCMath 擴充
 = bcmul("1234.56", "1.05", 4);  // 1296.2880(保留 4 位)
echo ;

最佳實踐

  1. 設計階段:金融相關欄位統一使用 DECIMAL(15, 4) 或視需求調整
  2. 程式端:Java 用 BigDecimal(搭配 getBigDecimal())、PHP 用 bcmath 系列函式
  3. 顯示端:輸出給使用者時再做格式化,儲存層保持完整精度

參考資料