NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Money for Laravel

Rounding & math helpers

All rounding uses PHP 8.4’s native \RoundingMode enum — the same one round() and bcround() take. Value objects default to HalfAwayFromZero as a constant and never read config; services read money.rounding (formatter, avgMoney) and money.exchange.rounding (conversions).

RoundingModeConfig value2.5-2.51.6-1.1
HalfAwayFromZerohalf_away_from_zero3-32-1
HalfTowardsZerohalf_towards_zero2-22-1
HalfEvenhalf_even2-22-1
HalfOddhalf_odd3-32-1
TowardsZerotowards_zero2-21-1
AwayFromZeroaway_from_zero3-32-2
PositiveInfinitypositive_infinity3-22-1
NegativeInfinitynegative_infinity2-31-2
use RoundlyConsulting\Money\Percentage;
use RoundlyConsulting\Money\Ratio;

$ten = Money::ofMajor('10', 'EUR');

$ten->divide(3);                                  // 3.33 EUR (HalfAwayFromZero)
$ten->divide(3, RoundingMode::PositiveInfinity);  // 3.34 EUR
$ten->multiply(Ratio::of(2, 3));                  // 6.67 EUR — exact ratio, one rounding
$ten->percentage(Percentage::fromBasisPoints(850)); // 0.85 EUR (8.5 %)

Ratio::of('1.0854');                // 5427/5000
Ratio::of(1, 3)->toDecimal(4);      // "0.3333"
Ratio::of(1, 3)->toExactDecimal();  // null — does not terminate
Percentage::of('8.5')->basisPoints(); // 850

Ratio and Percentage

Ratio is an exact rational — reduced, with a positive denominator and terms of up to 80 digits. Percentage is a non-negative decimal percent with up to 6 fraction digits (Percentage::of(), fromBasisPoints(), fromRatio()). Both feed multiply(), divide() and percentage() without a single float.

MinorUnits

Currency-less helpers for credits, points and provider SDK amounts — int|string in, strings out, scales 0..36:

use RoundlyConsulting\Money\Math\MinorUnits;

MinorUnits::normalize('007');          // "7"
MinorUnits::toDecimal(123450, 2);      // "1234.50"
MinorUnits::fromDecimal('10.5', 2);    // "1050" — excess precision needs a rounding mode
MinorUnits::rescale(123450, 2, 0);     // "1235"
MinorUnits::toInt('6747');             // 6747 — throws AmountOverflow outside int64

Rounding from your own config

RoundingModes maps snake_case config values onto the enum. A value that is not set (null or blank) takes the optional third-argument default, or throws when you pass none. Anything else — including the ambiguous half_up — throws InvalidMoneyConfiguration naming the key:

use RoundlyConsulting\Money\Support\RoundingModes;

RoundingModes::fromValue(config('shop.rounding'), 'shop.rounding'); // RoundingMode
RoundingModes::fromValue(config('shop.rounding'), 'shop.rounding', RoundingMode::HalfEven); // null or blank → HalfEven
RoundingModes::fromConfig('money.rounding');                        // RoundingMode::HalfAwayFromZero
RoundingModes::toValue(RoundingMode::HalfEven);                     // "half_even"

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.