PHP 遵循 IEEE 754 雙精度標準,浮點數以 64 位元儲存(1 位號、11 位指數、52 位尾數)。這導致許多十進位小數在二進位下無法精確表示,成為經典的「精度陷阱」。
<?php
$f = 0.57;
echo intval($f * 100); // 輸出 56,而非預期的 57
$f = 0.58;
var_dump(intval($f * 100)); // 輸出 57
以 0.57 為例,採「乘 2 取整」法轉二進位:
0.57 × 2 = 1.14 → 1 0.14 × 2 = 0.28 → 0 0.28 × 2 = 0.56 → 0 0.56 × 2 = 1.12 → 1 ... 無限循環,無法終止
52 位尾數只能截斷近似值:
0.569999999999999950.57999999999999996乘 100 後再 intval 截斷,自然得到 56 與 57。這不是 PHP Bug,而是 IEEE 754 固有特性。
| 方法 | 適用場景 | 注意事項 |
|---|---|---|
round($val, $precision) | 一般四捨五入需求 | 會四捨五入,非單純截斷 |
sprintf("%.Nf", $val) | 需固定小數位輸出 | 回傳字串,需再轉型 |
bcmath / gmp | 金融、科學計算等高精度場景 | 需安裝擴展,效能較低 |
| 整數運算(如以「分」為單位) | 貨幣計算 | 避開浮點數,最推薦 |
number_format() 或 sprintf() 格式化。abs($a - $b) < 1e-9。php.precision 僅影響輸出,不改變內部儲存值。掌握這些原理與技巧,即可從容應對 PHP 浮點數精度問題,避免踩坑。