Dividing a monetary amount equally can leave a remainder. For example, one hundred cents shared among three participants cannot give everyone the same integer number of cents. A useful allocation rule gives everyone the integer quotient, then distributes the remaining cents one at a time in a defined order.

This tutorial accepts amounts already expressed in cents. It avoids converting decimal money strings to floating-point numbers and does not attempt to implement currency conversion or tax rounding. The allocation conserves the total and keeps the largest and smallest shares at most one cent apart.

Prerequisites

Use a supported PHP 8 release with the command-line interpreter. The example was tested on PHP 8.3.6. Save this complete program as split.php.

<?php
declare(strict_types=1);
function splitCents(int $total, int $people): array {
    if ($total < 0 || $people < 1 || $people > 10000) {
        throw new InvalidArgumentException('invalid total or group size');
    }
    $base = intdiv($total, $people);
    $extra = $total % $people;
    $parts = [];
    for ($i = 0; $i < $people; $i++) {
        $parts[] = $base + ($i < $extra ? 1 : 0);
    }
    return $parts;
}
function check(bool $ok): void {
    if (!$ok) throw new RuntimeException('check failed');
}
check(splitCents(100, 3) === [34, 33, 33]);
check(splitCents(0, 2) === [0, 0]);
check(splitCents(2, 4) === [1, 1, 0, 0]);
foreach ([[1, 0], [-1, 2], [1, 10001]] as [$total, $people]) {
    try {
        splitCents($total, $people);
        throw new RuntimeException('invalid accepted');
    } catch (InvalidArgumentException $expected) {}
}
for ($n = 1; $n <= 20; $n++) {
    for ($cents = 0; $cents <= 100; $cents++) {
        $parts = splitCents($cents, $n);
        check(count($parts) === $n && array_sum($parts) === $cents);
        check(max($parts) - min($parts) <= 1);
    }
}
echo json_encode(splitCents(100, 3)), PHP_EOL;
echo "2020 conservation checks passed", PHP_EOL;

Run and expected output

php split.php
[34,33,33]
2020 conservation checks passed

Why the sum is exact

For nonnegative inputs, total equals people multiplied by the integer quotient plus the remainder. The loop creates people shares of the quotient and adds one to exactly remainder shares. Their sum therefore equals total. Earlier array positions receive any extra cents, making the result deterministic.

The nested test loops cover 101 totals for each of 20 group sizes. Each allocation checks the number of shares, the conserved sum and the maximum difference. Separate examples cover zero money, more participants than cents and invalid inputs. The checks throw exceptions directly, so their execution does not depend on PHP assertion configuration.

Edge cases and troubleshooting

The group-size cap is an application limit to bound the returned array. Adjust it only after considering memory use. Negative totals are rejected because refunds need a separately defined sign and remainder policy. The function does not parse incoming form data: validate and convert that data before calling it.

PHP integer capacity depends on the platform. Keep totals inside the deployed integer range and use an appropriate decimal or arbitrary-precision design if larger amounts are required. Some currencies use a minor unit other than one hundredth; the algorithm works with integer units, but the caller must choose the correct unit.

For repeated allocations, always favoring the first participant may be undesirable. Rotate or otherwise define the participant order before calling the function, and record that order with the transaction. Do not shuffle the returned values after associating them with people.

Primary references

Consult PHP's intdiv reference and integer documentation. Continue with PHP tutorials.