PHP 8.4: BCMath: New bcdivmod
function
The BCMath extension in PHP 8.4 introduces a new function named bcdivmod
that divides a given number by a given divisor, and returns both the quotient and remainder. The result is essentially identical to calling bcdiv
and bcmod
functions.
bcdivmod
can be used in use cases where both the the quotient and remainder necessary, and it avoids having to call bcdiv
and bcmod
functions separately.
The return value is an array, with the first value being the quotient and second value the remainder.
bcdivmod('42', '10');
// ["4", "2"]
bcdivmod
function synopsis
/**
* @param string $num1 Dividend, as a string.
* @param string $num2 Divisor, as a string.
* @param int|null $scale Number of digits after the decimal place in the
* remainder. If omitted or null, it will default to the scale set globally
* with the bcscale() function, or fallback bcmath.scale INI value
* (default to 0) if this has not been set.
*
* @return array
*/
function bcdivmod(string $num1, string $num2, ?int $scale = null): array {}
bcdivmod
is declared in the global namespace.- If the
scale
value isnull
, it inherits the scale value set with thebcscale
function, with a fallback to thebcmath.scale
INI value. - Return value is always an array.
- Passing
0
for the$num2
parameter throws aDivisionByZeroError
exception. - Passing a non-numeric string for
$num1
or$num2
parameters throw aValueError
exception saying the value is not well-formed.
bcdivmod
returns an array with the quotient (whole values) as a string, and the remainder as a string containing $scale
number of decimal values.
Usage Examples
bcdivmod("10", "10");
// ["1", "0"]
bcdivmod("10", "100");
// ["0", "10"]
// Using default bcmath.scale INI value = 0
bcdivmod("8957", "5.43242");
// ["1648", "4"]
// Setting scale value
bcdivmod("8957", "5.43242", 10);
// ["1648", "4.3718400000"]
bcdivmod("8957.5454312", "5.43242", 10);
// ["1648", "4.9172712000"]
bcdivmod("0", 42);
// ["0", "0"]
bcdivmod
error conditions
bcdivmod
function follows similar semantics as other functions in the BCMath extension. Passing non-numeric values throw a ValueError
exception, and because the type declaration of the $num1
and $num2
parameters are string
, it follows standard PHP type coercion and strict-type rules when declare(strict_types=1)
is in effect.
Passing zero as the divisor throws a DivisionByZeroError
:
bcdivmod("42", "0");
DivisionByZeroError: Division by zero
Passing non-numeric strings or INF
to $num1
or $num2
throws a ValueError
:
bcdivmod("42", "foobar");
ValueError: bcdivmod(): Argument #2 ($num2) is not well-formed.
Backward Compatibility Impact
bcdivmod
is a new function added to PHP 8.4 BCMath extension. Unless there is an existing global function with the same name, this change should not cause any backward-compatibility issues.
The following is a PHP polyfill that uses bcdiv
and bcmod
functions, and is compatible with PHP 8.0 and later:
/**
* @param string $num1 Dividend, as a string.
* @param string $num2 Divisor, as a string.
* @param int|null $scale Number of digits after the decimal place in the
* remainder. If omitted or null, it will default to the scale set globally
* with the bcscale() function, or fallback to bcmath.scale INI value (default to 0) if this has not been set.
*
* @return array
*/
function bcdivmod(string $num1, string $num2, ?int $scale = null): array {
if (!is_numeric($num1)) {
throw new \ValueError('Argument #1 ($num1) is not well-formed');
}
if (!is_numeric($num2)) {
throw new \ValueError('Argument #2 ($num2) is not well-formed');
}
if ($num2 === '0') {
throw new \DivisionByZeroError('Division by zero');
}
return [
\bcdiv($num1, $num2, 0),
\bcmod($num1, $num2, $scale),
];
}