四大取整函數對比
| 函數 | 行為 | 回傳型別 | 典型用途 |
ceil() | 向上取整 (天花板) | float | 分頁計算、資源配額向上 |
floor() | 向下取整 (地板) | float | 分頁索引、陣列索引 |
round() | 四捨五入 (可指定精度) | float | 金額顯示、統計數據 |
intval() | 截斷小數 (向零取整) | int | 型別轉換、ID 處理 |
詳細行為與範例
ceil() - 向上取整
<?php
echo ceil(4.3); // 5
echo ceil(9.999); // 10
echo ceil(-4.3); // -4 (向上 = 更接近正無窮)
echo ceil(-9.999); // -9
// 實用:分頁總頁數
$totalItems = 103;
$perPage = 20;
$totalPages = (int) ceil($totalItems / $perPage); // 6
?>
floor() - 向下取整
<?php
echo floor(4.3); // 4
echo floor(9.999); // 9
echo floor(-4.3); // -5 (向下 = 更接近負無窮)
echo floor(-9.999); // -10
// 實用:陣列隨機索引
$items = ['a', 'b', 'c', 'd', 'e'];
$randomIndex = (int) floor(mt_rand() / mt_getrandmax() * count($items));
?>
round() - 四捨五入 (支援精度)
<?php
// 基本四捨五入
echo round(3.4); // 3
echo round(3.5); // 4 (PHP 採用「銀行家捨入法」: .5 向偶數)
echo round(3.6); // 4
// 指定小數位數
echo round(1.95583, 2); // 1.96
echo round(1241757, -3); // 1242000 (負精度 = 整數位捨入)
// 銀行家捨入法示例
echo round(0.5); // 0 (偶數)
echo round(1.5); // 2 (偶數)
echo round(2.5); // 2 (偶數)
echo round(3.5); // 4 (偶數)
// PHP 8.0+ 可指定模式
echo round(1.5, 0, PHP_ROUND_HALF_UP); // 2 (傳統四捨五入)
echo round(1.5, 0, PHP_ROUND_HALF_DOWN); // 1
echo round(1.5, 0, PHP_ROUND_HALF_EVEN); // 2 (預設,銀行家)
?>
intval() - 截斷轉整數
<?php
echo intval(4.3); // 4
echo intval(4.6); // 4 (直接截斷,非四捨五入)
echo intval(-4.3); // -4 (向零)
echo intval(-4.6); // -4
// 字串轉換規則
echo intval('123'); // 123
echo intval('123abc'); // 123 (遇非數字停止)
echo intval('abc123'); // 0 (開頭非數字)
echo intval('-123'); // -123
echo intval('1.9'); // 1 (小數點視為非數字)
// 基數轉換 (第二參數)
echo intval('1010', 2); // 10 (二進制)
echo intval('FF', 16); // 255 (十六進制)
echo intval('77', 8); // 63 (八進制)
?>
浮點數精度陷阱 (必讀)
<?php
// 經典問題
echo 0.1 + 0.2; // 0.30000000000000004
echo floor(0.1 + 0.2); // 0 (非預期的 0!)
echo intval(0.1 + 0.2); // 0
// 原因:IEEE 754 二進制無法精確表示 0.1、0.2
// 解決方案:
// 1. BCMath 高精度數學 (推薦金融計算)
echo bcadd('0.1', '0.2', 2); // 0.30
echo bcmul('19.99', '100', 0); // 1999 (分為單位)
// 2. 整數運算 (以分/毫為單位)
$priceCents = 1999; // 19.99 元
$quantity = 3;
$totalCents = $priceCents * $quantity; // 5997 分 = 59.97 元
// 3. round() 修正顯示
echo round(0.1 + 0.2, 2); // 0.3
// 4. number_format 格式化輸出
echo number_format(0.1 + 0.2, 2); // "0.30"
?>
金融/電商計算最佳實踐
<?php
class Money {
private int $cents; // 內部以最小單位 (分) 儲存
public static function fromDollars(float|string $dollars): self {
$cents = (int) round((float) $dollars * 100);
return new self($cents);
}
public function __construct(int $cents) {
$this->cents = $cents;
}
public function add(self $other): self {
return new self($this->cents + $other->cents);
}
public function multiply(float $factor): self {
return new self((int) round($this->cents * $factor));
}
public function toDollars(int $decimals = 2): string {
$dollars = $this->cents / 100;
return number_format($dollars, $decimals, '.', ',');
}
public function __toString(): string {
return $this->toDollars();
}
}
// 使用
$price = Money::fromDollars('19.99');
$total = $price->multiply(3)->add(Money::fromDollars('5.00'));
echo $total; // "64.97"
?>
函數選擇決策樹
需要四捨五入到指定小數位?
├─ 是 → round($val, $precision) [PHP 8+ 可指定模式]
└─ 否
├─ 需向上取整? → ceil($val)
├─ 需向下取整? → floor($val)
├─ 需轉為整數型別? → (int) $val 或 intval($val)
└─ 金融計算? → BCMath / 整數分單位 / Money 物件
常見錯誤對照表
| 程式碼 | 結果 | 問題 | 修正 |
(int) (19.99 * 100) | 1998 | 浮點誤差導致截斷 | (int) round(19.99 * 100) |
floor(0.1 + 0.2) | 0 | 浮點誤差 | floor(bcadd('0.1', '0.2', 10)) |
round(2.5) | 2 | 銀行家捨入法 | round(2.5, 0, PHP_ROUND_HALF_UP) |
intval('1.9') | 1 | 字串遇點停止 | (int) round('1.9') |
理解浮點數本質與各函數行為差異,選擇正確工具處理數值,是避免生產環境離奇 Bug 的關鍵。金融計算請務必使用整數分單位或 BCMath。