number_format() 預設四捨五入,若需無條件捨去(向下取整到指定小數位),需技巧處理。
| 目標位數 | 偏移量 | 說明 |
|---|---|---|
| 小數 1 位 | -0.05 | 使第 2 位 < 5,避免進位 |
| 小數 2 位 | -0.005 | 使第 3 位 < 5 |
| 小數 n 位 | -0.5 × 10⁻ⁿ | 通用公式 |
| 整數 | -0.5 | 使小數部份 < 0.5 |
/**
* 無條件捨去到指定小數位
* @param float $num
* @param int $precision 小數位數 (0 為整數)
* @param string $decPoint 小數點符號
* @param string $thousandsSep 千分位符號
* @return string
*/
function number_floor(float $num, int $precision = 0, string $decPoint = '.', string $thousandsSep = ','): string {
if ($precision < 0) $precision = 0;
$offset = 0.5 * (10 ** -$precision);
return number_format($num - $offset, $precision, $decPoint, $thousandsSep);
}
// 測試
echo number_floor(123456.6588, 2); // 123,456.65
echo number_floor(123456.6588, 0); // 123,456
echo number_floor(-1.999, 2); // -1.99 (負數向零方向捨去)
?>
| 方法 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 減法偏移 + number_format | 一行搞定、格式化內建 | 浮點數精度邊界極少數誤差 | 一般金額顯示 |
| bcmath: bcdiv/bcadd | 任意精度、無浮點誤差 | 需擴展、字串運算較慢 | 金融級計算 |
| floor($num * 10ⁿ) / 10ⁿ | 純數學、無格式化 | 需自行格式化輸出 | 後續仍需運算 |
| sprintf('%.2f', floor($num*100)/100) | 標準函式 | 同浮點誤差 | 簡單輸出 |
上述方法對負數為向零捨去(-1.999 → -1.99)。若需向下取整(-1.999 → -2.00),改用 floor() 數學法。