萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP 數字格式化完全手冊:四捨五入、保留小數、取整、進位與精度陷阱

核心函數速查表

函數功能回傳型別典型用途
round($val, $precision, $mode)四捨五入(支援指定精度與模式)float/int金額計算、統計顯示
ceil($val)無條件進位(向上取整)float/int分頁總頁數、資源配額
floor($val)無條件捨去(向下取整)float/int索引計算、分桶
sprintf($format, $val)格式化字串(不輸出,返回字串)string顯示格式化、固定小數位
number_format($val, $decimals, $dec_point, $thousands_sep)千分位格式化string金額顯示、報表匯出
intval($val) / (int)$val截斷轉整數(向零取整)int型別轉換、索引計算

保留 N 位小數:四捨五入 vs 截斷

四捨五入(推薦 round 或 sprintf)

<?php
$num = 0.0215489;

// round:返回數值型別
echo round($num, 3);           // 0.022 (float)

// sprintf:返回字串,保證位數(含尾隨 0)
echo sprintf("%.3f", $num);    // "0.022" (string)

// number_format:千分位 + 固定小數
echo number_format(1234.5678, 2, '.', ','); // "1,234.57"
?>

截斷不四捨五入(直接切捨)

<?php
$num = 0.0215489;

// 方法 1:sprintf 多取一位再切字串(不推薦,易出錯)
echo substr(sprintf("%.4f", $num), 0, -1); // "0.021"

// 方法 2:數學運算(精確、效能佳)
$precision = 3;
$factor = 10 ** $precision;
echo floor($num * $factor) / $factor;      // 0.021 (float)

// 方法 3:bcmath 高精度(任意精度)
echo bcdiv(bcmul($num, '1000', 0), '1000', 3); // "0.021"
?>

取整函數深度對比

<?php
$vals = [4.3, 4.7, -4.3, -4.7, 9.999, -9.999];

foreach ($vals as $v) {
    echo "值: $v\n";
    echo "  ceil:  " . ceil($v)  . "\n";   // 向上(正無窮)
    echo "  floor: " . floor($v) . "\n";   // 向下(負無窮)
    echo "  round: " . round($v) . "\n";   // 四捨五入
    echo "  intval:" . intval($v) . "\n";  // 向零截斷
    echo "  (int): " . (int)$v   . "\n";   // 同 intval
    echo "\n";
}

/* 輸出摘要:
值: 4.3   ceil:5  floor:4  round:4  intval:4
值: 4.7   ceil:5  floor:4  round:5  intval:4
值: -4.3  ceil:-4 floor:-5 round:-4 intval:-4
值: -4.7  ceil:-4 floor:-5 round:-5 intval:-4
值: 9.999 ceil:10 floor:9  round:10 intval:9
值: -9.999 ceil:-9 floor:-10 round:-10 intval:-9
*/
?>

關鍵差異總結

  • ceil:永遠向 正無窮 方向(數值變大)
  • floor:永遠向 負無窮 方向(數值變小)
  • round:四捨五入,0.5 進位(PHP 採用銀行家捨入?否,PHP 為標準四捨五入,round(2.5)=3)
  • intval/(int):向 零 截斷(正數同 floor,負數同 ceil)

round() 進階模式(PHP 5.3+)

<?php
// 模式常數
// PHP_ROUND_HALF_UP   : 0.5 遠離零進位(預設)
// PHP_ROUND_HALF_DOWN : 0.5 向零進位
// PHP_ROUND_HALF_EVEN : 銀行家捨入(到最近偶數)
// PHP_ROUND_HALF_ODD  : 到最近奇數

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
echo round(2.5, 0, PHP_ROUND_HALF_EVEN); // 2(銀行家捨入)

// 負數精度:十位、百位捨入
echo round(1241757, -3);  // 1242000(千位捨入)
?>

浮點數精度陷阱(必讀)

<?php
$f = 0.58;
var_dump(intval($f * 100));  // int(57) 而非 58!

// 原因:0.58 二進制無法精確表示
// 0.58 * 100 = 57.99999999999999...
// intval 向零截斷 → 57

// 正確做法:
echo round($f * 100);        // 58(四捨五入)
echo intval(round($f * 100)); // 58
// 或使用 bcmath
echo bcmul($f, '100', 0);    // "58"
?>

金額計算鐵律

  1. 💰 資料庫存「分」為整數:5800 代表 58.00 元
  2. 🧮 運算使用 BCMath 或整數運算:避免浮點誤差
  3. 📝 顯示時才格式化:number_format($cents/100, 2)
  4. 🚫 絕不直接用 float 存儲/運算金額

實用片段庫

<?php
// 1. 格式化價格(分轉元,兩位小數,千分位)
function fmtPrice(int $cents): string {
    return number_format($cents / 100, 2, '.', ',');
}

// 2. 分頁總頁數
function totalPages(int $total, int $perPage): int {
    return (int)ceil($total / $perPage);
}

// 3. 百分比顯示(保留 1 位小數)
function fmtPct(float $rate): string {
    return sprintf('%.1f%%', $rate * 100);
}

// 4. 安全除法(避免除零)
function safeDiv(float $a, float $b, float $default = 0): float {
    return $b !== 0 ? $a / $b : $default;
}

// 5. 範圍限制
function clamp(float $val, float $min, float $max): float {
    return max($min, min($max, $val));
}
?>

總結

PHP 提供豐富的數字處理函數,關鍵在於選對工具、懂精度陷阱、分層處理:資料層用整數(分)、運算層用 BCMath/整數、展示層用 sprintf/number_format。牢記 0.58 * 100 !== 58,金額計算永遠不碰原生浮點數,是 PHP 開發者的基本素養。

copyright © 萬盛學電腦網 all rights reserved