Функции округления PHP: round, ceil, floor, number_format, bcmath
Основные функции округления PHP
Для работы с округлением чисел в PHP существует несколько встроенных функций. Каждая из них решает конкретную задачу: от простого округления до математического, вверх, вниз или с заданной точностью. Основной функцией считается round(), которая поддерживает режимы округления (PHP 8+).
Как правильно округлить число с контролем способа округления (математическое, от нуля, к нулю)?
Начиная с PHP 8.0 функция round() принимает третий аргумент - константу режима округления:
$number = 2.5;
echo round($number, 0, PHP_ROUND_HALF_UP); // 3 (математическое)
echo round($number, 0, PHP_ROUND_HALF_DOWN); // 2 (в меньшую сторону от 0.5)
echo round($number, 0, PHP_ROUND_HALF_EVEN); // 2 (bank rounding)
echo round($number, 0, PHP_ROUND_HALF_ODD); // 3Php округлить число (округление числа в php)
3 2 2 3
Проблема: в PHP до 8.0 режим всегда был PHP_ROUND_HALF_UP (по умолчанию). При обновлении кода на более старых версиях использование третьего аргумента вызовет ошибку. Решение: проверять версию PHP или использовать собственную реализацию.
Типичная ошибка: путаница с точностью (второй аргумент). По умолчанию 0 знаков после запятой.
Как округлить число всегда в большую сторону (потолок)?
Функция ceil() округляет дробное число до ближайшего большего целого (независимо от знака):
echo ceil(4.2); // 5
echo ceil(-4.2); // -4 (так как -4 больше -4.2)
5 -4
Проблема: с отрицательными числами результат может быть неожиданным - ceil(-4.2) даёт -4, а не -5. Если требуется округление «от нуля» для положительных и отрицательных чисел, используйте комбинацию с abs().
Как округлить число всегда в меньшую сторону (пол)?
Функция floor() округляет до ближайшего меньшего целого:
echo floor(4.9); // 4
echo floor(-4.9); // -5
4 -5
Проблема: floor(-4.9) даёт -5, что соответствует «вниз» (к минус бесконечности). Если нужно «вниз» к нулю, используйте intval() или (int) для положительных, а для отрицательных - ceil.
Как округлить число до заданного количества десятичных знаков с форматированием (с разделителем тысяч)?
Функция number_format() форматирует число с округлением:
echo number_format(12345.6789, 2, '.', ' '); // 12 345.68
echo number_format(12345.6789, 0, ',', '.'); // 12.346
12 345.68 12.346
Проблема: number_format() всегда использует PHP_ROUND_HALF_UP для округления. На старых версиях нельзя сменить режим. Решение: предварительно применить round() с нужным режимом, затем передать результат в number_format (но тогда может потеряться точность из-за двойного преобразования). Лучше использовать пользовательскую форматирующую функцию.
Как округлить число до ближайшего целого с заданным шагом (например, до десятков, сотен)?
Для округления до кратного шагу используют round($number / $step) * $step:
$step = 10;
echo round(24 / $step) * $step; // 20
echo round(25 / $step) * $step; // 30
echo round(26 / $step) * $step; // 30
20 30 30
Проблема: такой метод округляет по математическому правилу. Для явного округления вверх/вниз используйте ceil() / floor() с тем же множителем: ceil(24/10)*10 = 30.
Как округлить число с произвольной точностью без ошибок float (например, для финансов)?
Для точных десятичных вычислений применяют расширение BCMath. Функция bcround() (реализуют вручную) или bcmath::add с round:
function bcround($number, $precision = 0) {
$multiplier = bcpow('10', $precision);
return bcdiv(bcmul($number, $multiplier, $precision+1), $multiplier, $precision);
}
echo bcround('2.345', 2); // 2.35 (правильно)
echo 2.345; // исходный float может быть неточным
2.35 2.345
Проблема: BCMath работает со строками, поэтому входные значения нужно передавать как строки. Если число получено из float (например, 2.345), оно уже имеет погрешность, и bcround округлит уже неточное значение. Решение: работать с исходными данными как строками (например, из базы данных или ввода пользователя).
Как округлить число до целого, отбросив дробную часть (целочисленное деление)?
Используют intdiv() для целочисленного деления или приведение типов (int), floor() для положительных:
echo intdiv(10, 3); // 3 (целая часть от деления)
echo (int)(10/3); // 3
echo floor(10/3); // 3
3 3 3
Проблема: intdiv() не округляет, а только отбрасывает дробную часть. Для отрицательных чисел (int)(-10/3) даёт -3, а intdiv(-10,3) даёт -3 (но в PHP 8 intdiv с отрицательными работает корректно).
Как округлить число с использованием sprintf (форматирование строки)?
Функция sprintf() также округляет при форматировании:
echo sprintf('%01.2f', 2.345); // 2.35 (округляет)
echo sprintf('%01.0f', 2.5); // 3
echo sprintf('%01.0f', 2.49); // 2
2.35 3 2
Проблема: sprintf округляет по правилу PHP_ROUND_HALF_UP, изменить режим нельзя. Кроме того, результат - строка, а не число. Для дальнейших вычислений потребуется преобразование.
Расширенные примеры округления в PHP
Ниже приведены дополнительные, менее тривиальные сценарии работы с округлением.
Округление до кратного 0.5
$number = 2.3;
$rounded = round($number * 2) / 2;
echo $rounded; // 2.5
echo round(2.8 * 2) / 2; // 3.0
echo round(2.0 * 2) / 2; // 2.0
2.5 3.0 2.0
Пояснение: умножение на 2, округление до целого, затем деление на 2 даёт округление до 0.5.
Округление вверх до кратного заданного числа (например, до следующих 5)
function ceilTo($value, $multiple) {
return ceil($value / $multiple) * $multiple;
}
echo ceilTo(12, 5); // 15
echo ceilTo(10, 5); // 10
echo ceilTo(13.2, 5); // 15
15 10 15
Округление вниз до кратного
function floorTo($value, $multiple) {
return floor($value / $multiple) * $multiple;
}
echo floorTo(12, 5); // 10
echo floorTo(10, 5); // 10
echo floorTo(13.2, 5); // 10
10 10 10
Банковское округление (round half to even) - собственный класс для старых версий PHP
function bankRound($value, $precision = 0) {
$multiplier = pow(10, $precision);
$value *= $multiplier;
$intPart = floor($value);
$fraction = $value - $intPart;
if ((abs($fraction) < 0.5) || (abs($fraction) == 0.5 && $intPart % 2 == 0)) {
$result = $intPart;
} else {
$result = $intPart + ($value > 0 ? 1 : -1);
}
return $result / $multiplier;
}
echo bankRound(2.5, 0); // 2
echo bankRound(3.5, 0); // 4
echo bankRound(2.51, 0); // 3
2 4 3
Округление с учётом погрешности float (использование precision ini)
ini_set('precision', 20);
$value = 0.1 + 0.2; // 0.30000000000000004
echo round($value, 1); // 0.3
echo round($value, 2); // 0.3
0.3 0.3
Пояснение: round может скрыть мелкие погрешности, но не устраняет их при сравнениях.
Округление до ближайшего целого с учётом знака (от нуля / к нулю)
function roundAwayFromZero($value, $precision = 0) {
$sign = $value >= 0 ? 1 : -1;
return round(abs($value), $precision) * $sign;
}
echo roundAwayFromZero(2.5, 0); // 3
echo roundAwayFromZero(-2.5, 0); // -3
echo roundAwayFromZero(-2.49, 0); // -2
3 -3 -2
Округление до целого с отбрасыванием дробной части (truncate)
$value = 3.999;
echo (int)$value; // 3
echo floor($value); // 3 (для положительных)
echo intval($value); // 3
echo 0 + $value; // 3.999 (не округляет)
3 3 3 3.999
Округление с произвольной точностью с помощью библиотеки Decimal (PECL)
// Предположим, установлен ext-decimal
$value = new Decimal\Decimal('2.345');
echo (string)$value->round(2); // 2.35
echo (string)$value->floor(); // 2
echo (string)$value->ceil(); // 3
2.35 2 3