前言
浮點數運算存在精度誤差(如 0.1 + 0.2 !== 0.3),直接用 == 比較不可靠。標準做法是設定容許誤差值(epsilon),若絕對差小於 epsilon 則視為相等。
基本比較函數
<?php
/**
* 浮點數近似相等比較
*
* @param float $a
* @param float $b
* @param float $epsilon 容許誤差(預設 1e-5)
* @return bool
*/
function floatEquals(float $a, float $b, float $epsilon = 1e-5): bool {
return abs($a - $b) < $epsilon;
}
// 測試
$a = 1.00000001;
$b = 1.00000000;
var_dump(floatEquals($a, $b)); // true (差 1e-8 < 1e-5)
var_dump(floatEquals($a, $b, 1e-10)); // false (差 1e-8 > 1e-10)
$c = 0.1 + 0.2;
$d = 0.3;
var_dump($c == $d); // false
var_dump(floatEquals($c, $d)); // true
?>
選擇適當的 Epsilon
| 場景 | 建議 Epsilon | 說明 |
| 一般貨幣計算(分精度) | 0.001 | 0.01 元 = 1 分,誤差不超過 0.1 分 |
| 科學計算(雙精度) | 1e-10 ~ 1e-12 | 視運算複雜度調整 |
| 通用預設 | 1e-5 | PHP 手冊建議值 |
進階:相對誤差比較(適用於大數值)
<?php
function floatEqualsRelative(float $a, float $b, float $epsilon = 1e-5): bool {
$diff = abs($a - $b);
if ($diff < $epsilon) return true; // 絕對誤差已足夠小
// 相對誤差:差值 / max(|a|, |b|)
$relativeDiff = $diff / max(abs($a), abs($b));
return $relativeDiff < $epsilon;
}
// 大數值測試
$a = 1_000_000.01;
$b = 1_000_000.02;
var_dump(floatEquals($a, $b)); // false (差 0.01 > 1e-5)
var_dump(floatEqualsRelative($a, $b)); // true (相對差 ~1e-8)
?>
BCMath 高精度替代方案
<?php
// 需安裝 bcmath 擴展
$a = '0.1';
$b = '0.2';
$c = '0.3';
$sum = bcadd($a, $b, 10); // 保留 10 位小數
var_dump(bccomp($sum, $c, 10) === 0); // true
?>
財務、金融系統強烈建議使用 BCMath 或整數分單位計算,避免浮點數誤差根源。
總結
浮點數比較必須使用容許誤差機制。floatEquals() 封裝此邏輯,配合相對誤差版本可涵蓋更廣泛場景。希望本文對您的 PHP 程式設計有所幫助。
- 上一篇文章: PHP 依指定長度分割字串並插入分隔符(如千分位格式化)
- 下一篇文章: PHP 讀取 CSV 並輸出 HTML 表格的完整範例
Copyright ©
程式碼之家 All Rights Reserved