PHP 8.4: BCMath: New bcdivmod function

Version8.4
TypeNew Feature

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 is null, it inherits the scale value set with the bcscale function, with a fallback to the bcmath.scale INI value.
  • Return value is always an array.
  • Passing 0 for the $num2 parameter throws a DivisionByZeroError exception.
  • Passing a non-numeric string for $num1 or $num2 parameters throw a ValueError 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),
    ];
}

bcdivmod RFC Discussion Implementation