首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 浮點數運算精度陷阱與 BCMath 高精度解決方案

     編輯:PHP 綜合知識

經典面試題:var_dump((0.1 + 0.7) == 0.8); 輸出 bool(false)。這不是 Bug,而是 IEEE 754 雙精度浮點數標準 導致的必然結果——十進位小數無法精確用二進位有限位數表示(如 0.1 在二進位是無限循環小數)。

為什麼會不準?

PHP 手冊明確警告:永遠不要相信浮點數精確到最後一位,也永遠不要直接比較兩個浮點數是否相等。

<?php
$a = 0.1; $b = 0.7;
var_dump($a + $b);           // float(0.8) 顯示正常
var_dump(($a + $b) == 0.8);  // bool(false) 實際為 0.7999999999999999
var_dump(floor((0.1+0.7)*10)); // int(7) 而非預期 8
?>

解決方案:BCMath 任意精度數學

PHP 內建 BCMath 擴展(通常預設開啟)提供字串級高精度運算,避開浮點誤差。

常用函數對照表

運算浮點數寫法BCMath 寫法說明
加法$a + $bbcadd($a, $b, $scale)$scale 為小數位數
減法$a - $bbcsub($a, $b, $scale)
乘法$a * $bbcmul($a, $b, $scale)
除法$a / $bbcdiv($a, $b, $scale)需指定 $scale,否則截斷
取模$a % $bbcmod($a, $b)
冪次$a ** $bbcpow($a, $b, $scale)
比較$a == $bbccomp($a, $b, $scale)返回 -1/0/1

修正範例

<?php
$a = '0.1'; $b = '0.7'; // BCMath 接受字串參數
$sum = bcadd($a, $b, 2); // '0.80'
var_dump($sum == '0.8'); // bool(true) ✅

// 金額計算最佳實踐:統一用分(整數)或 BCMath
$price1 = '19.99'; $price2 = '0.01';
$total = bcadd($price1, $price2, 2); // '20.00'
?>

進階:設定全域預設小數位

<?php
bcscale(2); // 後續 bcadd 等可省略 $scale 參數
echo bcadd('0.1', '0.7'); // 0.80
?>

GMP 擴展替代方案

對於大整數運算(如加密、階乘),gmp_* 函數效能更優:

<?php
$n = gmp_init('12345678901234567890');
echo gmp_strval(gmp_mul($n, $n)); // 大整數乘法
?>

總結建議

  1. 涉及金額、匯率、精度敏感計算 → 必用 BCMath(字串輸入/輸出)。
  2. 純整數大數運算 → GMP。
  3. 一般科學計算、圖形渲染 → 原生 float 可接受,但比較時用 abs($a-$b) < 1e-9 容差判斷。
  4. 資料庫儲存金額 → DECIMAL(19,4),勿用 FLOAT/DOUBLE。

掌握精度陷阱與工具選型,是 PHP 後端工程師的基本功。

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