Целочисленное деление в PHP: как получить частное без остатка
Основы целочисленного деления в PHP
При работе с числами в PHP часто возникает необходимость разделить одно число на другое так, чтобы результатом была только целая часть, без учёта остатка. Такое деление называется целочисленным. В PHP для этого существует несколько подходов, каждый из которых имеет свои особенности.
Как выполнить деление нацело с помощью встроенного оператора?
Наиболее эффективным и читаемым способом является использование оператора intdiv. Он возвращает целое число (int), полученное в результате деления первого аргумента на второй, отбрасывая дробную часть в сторону нуля.
<?php
$result = intdiv(10, 3);
echo $result; // 3
?>Php модуль числа (модуль числа в php (abs))
3
без остатка php (деление без остатка в php)
Оператор intdiv работает с целыми числами, но при передаче чисел с плавающей точкой они сначала преобразуются в целые. Важно помнить, что если делитель равен нулю, будет выброшено исключение DivisionByZeroError.
Типичная ошибка – деление на ноль. Решение – проверка делителя перед вызовом intdiv.
<?php
$a = 10;
$b = 0;
if ($b !== 0) {
$result = intdiv($a, $b);
} else {
echo 'Деление на ноль';
}
?>Как получить целую часть деления с помощью приведения к int?
Можно использовать обычное деление / и затем привести результат к целому типу с помощью (int) или intval(). Этот способ возвращает целую часть, отбрасывая дробную часть в сторону нуля, подобно intdiv.
<?php
$a = 10;
$b = 3;
$result = (int)($a / $b);
echo $result; // 3
?>Однако такой подход менее явный и может привести к путанице при чтении кода. Кроме того, если $a и $b – большие числа, результат деления может быть с плавающей точкой, что может вызвать потерю точности.
Проблема: при использовании float возможно неверное округление для очень больших чисел, выходящих за пределы точности double.
<?php
$a = 9999999999999999999;
$b = 1;
echo (int)($a / $b); // может вывести неверное значение из-за потери точности
?>Решение – использовать intdiv, который работает с целыми числами как с bigint при необходимости (при сборке с поддержкой GMP).
Как выполнить деление без остатка с округлением вниз для положительных чисел?
Функция floor() округляет число вниз до ближайшего целого. Для положительных чисел результат деления и последующее применение floor даёт целую часть. Однако для отрицательных чисел поведение отличается – floor округляет в сторону минус бесконечности, тогда как intdiv отбрасывает дробную часть в сторону нуля.
<?php
$a = 10;
$b = 3;
$result = floor($a / $b);
echo $result; // 3
// Для отрицательных:
echo floor(-10 / 3); // -4, а intdiv(-10,3) даст -3
?>Поэтому floor() подходит только для случаев, когда гарантированно работаем с положительными числами, и нужно именно округление вниз (в сторону меньшего).
Какие ещё существуют способы целочисленного деления?
Для работы с очень большими числами или строками можно использовать функцию bcdiv с параметром scale=0. Она выполняет деление с произвольной точностью и возвращает строку.
<?php
$a = '10000000000000000000';
$b = '3';
echo bcdiv($a, $b, 0); // 3333333333333333333
?>Этот метод удобен для экономических расчётов, где важна точность больших чисел.
Расширенные примеры работы с целочисленным делением
Сравнение поведения intdiv и приведения типов на отрицательных числах
<?php
$a = -10;
$b = 3;
echo 'intdiv: ' . intdiv($a, $b) . PHP_EOL; // -3
echo '(int) деления: ' . (int)($a / $b) . PHP_EOL; // -3
echo 'floor: ' . floor($a / $b) . PHP_EOL; // -4
echo 'ceil: ' . ceil($a / $b) . PHP_EOL; // -3
?>intdiv: -3 (int) деления: -3 floor: -4 ceil: -3
Как видно, floor даёт результат, отличный от intdiv, поэтому для единообразного поведения по стандарту целочисленного деления (округление к нулю) следует использовать intdiv или (int).
Обработка деления на ноль с исключением
<?php
try {
$result = intdiv(5, 0);
} catch (DivisionByZeroError $e) {
echo 'Ошибка: ' . $e->getMessage();
}
?>Ошибка: Division by zero
В отличие от обычного деления, где деление на ноль генерирует предупреждение и возвращает false или INF, intdiv генерирует исключение. Это делает код более безопасным.
Работа с числами с плавающей точкой
<?php
$a = 7.9;
$b = 2.1;
$resultIntDiv = intdiv($a, $b); // сначала преобразует в int: 7 и 2 -> 3
$resultCast = (int)($a / $b); // 7.9/2.1≈3.7619 -> 3
echo "intdiv: $resultIntDiv\n";
echo "(int): $resultCast";
?>intdiv: 3 (int): 3
Обратите внимание: intdiv отбрасывает дробные части операндов перед делением, поэтому результат может отличаться от ожидаемого. Если нужно сначала выполнить деление с плавающей точкой, а затем отбросить дробную часть, лучше использовать (int)($a / $b).
Целочисленное деление с остатком (проверка кратности)
<?php
function isEven($number) {
return $number % 2 === 0;
}
function divideWithoutRemainder($dividend, $divisor) {
if ($divisor === 0) {
throw new InvalidArgumentException('Деление на ноль');
}
$quotient = intdiv($dividend, $divisor);
$remainder = $dividend - $quotient * $divisor;
return [$quotient, $remainder];
}
list($q, $r) = divideWithoutRemainder(17, 5);
echo "Частное: $q, остаток: $r";
?>Частное: 3, остаток: 2
Так можно вручную получить одновременно частное и остаток, если это необходимо.
Использование bcdiv для чисел за пределами int
<?php
$a = '12345678901234567890';
$b = '987654321';
$result = bcdiv($a, $b, 0);
echo $result; // 12499999, в виде строки
?>12499999
bcdiv позволяет работать с числами произвольной длины, не теряя точности. Это важно для финансовых и научных расчётов.