bcmath when the money arithmetic has to be exact

A float cannot hold 0.07 exactly, so adding it a hundred times does not produce 7. This is invisible on a single line item and unavoidable on an invoice total, a VAT breakdown or a reconciliation report that has to agree with a bank statement to the cent. bcmath does the arithmetic on decimal strings instead, at a scale you nominate.

$total = 0.0;

for ($i = 0; $i < 100; $i++) {
    $total += 0.07;
}

var_dump($total === 7.0);        // false

$total = '0.00';

for ($i = 0; $i < 100; $i++) {
    $total = bcadd($total, '0.07', 2);
}

var_dump($total === '7.00');     // true

bcmul('19.99', '3', 2);          // '59.97'
bccomp('0.30', '0.3', 2);        // 0 — equal at scale 2

Every argument and every result is a string, which is what makes it exact and also what makes it easy to defeat: a value that has already been through json_decode(), a PDO column fetched as a float, or a stray arithmetic operator anywhere upstream has lost the precision before bcmath ever sees it. Watch bcdiv() in particular — it truncates at the scale rather than rounding, so a percentage split needs the rounding written out explicitly. It is also perhaps two orders of magnitude slower than native arithmetic, which is irrelevant for an order total and disqualifying inside a loop over a million rows. Where the currency has fixed minor units, storing integer cents and dividing once at the edge is simpler and faster; bcmath earns its keep when division, percentages and multi-currency scales are involved.