Rounding

Rounding and the RoundingMode Enum

round($num, $precision, $mode) rounds to $precision decimal places (negative values round to tens or hundreds); floor() and ceil() return whole-number floats. Since PHP 8.4 $mode accepts the RoundingMode enum, which renames the PHP_ROUND_* constants (HALF_UP is now HalfAwayFromZero, the default) and adds four directed modes.

Every RoundingMode case, plus precision and binary edge cases (round.php)PHP
<?php
$values = [2.5, 3.5, -2.5, 2.4, -2.6];
printf("%-17s%s\n", 'mode', implode('', array_map(fn($v) => sprintf('%6s', $v), $values)));
foreach (RoundingMode::cases() as $mode) {
    printf("%-17s%s\n", $mode->name,
        implode('', array_map(fn($v) => sprintf('%6s', round($v, 0, $mode)), $values)));
}
echo round(1234.5678, 2), ' ', round(1234.5678, -2), ' ', round(0.285, 2), ' ',
    sprintf('%.2f', 0.285), ' ', json_encode([floor(-2.5), ceil(-2.5)]), "\n";
Output
mode                2.5   3.5  -2.5   2.4  -2.6
HalfAwayFromZero      3     4    -3     2    -3
HalfTowardsZero       2     3    -2     2    -3
HalfEven              2     4    -2     2    -3
HalfOdd               3     3    -3     2    -3
TowardsZero           2     3    -2     2    -2
AwayFromZero          3     4    -3     3    -3
NegativeInfinity      2     3    -3     2    -3
PositiveInfinity      3     4    -2     3    -2
1234.57 1200 0.29 0.28 [-3,-2]

HalfEven (banker's rounding) keeps long columns of totals from drifting. The directed modes work at any precision: round($fee, 2, RoundingMode::PositiveInfinity) is a ceiling to the cent. round() rounds the decimal you wrote (0.29), while sprintf('%.2f') rounds the stored 0.28499999... (0.28); PHP 8.4 rewrote this code and fixed an old "pre-rounding" bug. number_format() rounds like round() (printf and Formatting). Round once, at display or storage.