brick/math
Arbitrary-precision math for PHP. Work with big integers, decimals and rationals reliably, with automatic acceleration via GMP or BCMath when available. PHP 8.2+ supported. Stable 0.x release cycles suitable for production.
Installation:
composer require brick/math
Ensure PHP ≥8.2 (or use compatible versions for older PHP).
First Use Case: Handle arbitrary-precision arithmetic where native PHP types fail (e.g., financial calculations, cryptography, or large-scale scientific computations).
use Brick\Math\BigDecimal;
$amount = BigDecimal::of('1234567890.1234567890');
$taxRate = BigDecimal::of('0.075');
$total = $amount->multipliedBy($taxRate)->plus($amount);
Key Entry Points:
BigInteger for whole numbers (e.g., IDs, hashes).BigDecimal for precise decimals (e.g., money, measurements).BigRational for fractions (e.g., ratios, probabilities).RoundingMode for controlling precision (e.g., HalfUp, Down).Where to Look First:
BigDecimal::of(), dividedBy()).0.15.0 removed float support).Precision-Critical Calculations:
$price = BigDecimal::of('999999999999.99');
$discount = BigDecimal::of('0.15'); // 15%
$finalPrice = $price->multipliedBy($discount)->plus($price);
BigInteger for large primes or modular arithmetic (e.g., RSA keys):
$modulus = BigInteger::of('123456789012345678901234567890');
$result = $modulus->modPow($exponent, $modulus);
Data Migration/Validation:
float/double data to BigDecimal to avoid floating-point errors:
$legacyFloat = 0.1 + 0.2; // 0.30000000000000004
$safeDecimal = BigDecimal::fromFloatExact($legacyFloat);
Chaining and Immutability:
$result = BigDecimal::of('100')
->dividedBy('3', 2, RoundingMode::HalfUp)
->plus('5')
->multipliedBy('2');
Rounding Strategies:
RoundingMode for consistent behavior (e.g., BankersRounding for accounting):
$tax = BigDecimal::of('123.456')->dividedBy('4', 2, RoundingMode::Bankers);
Interoperability:
$string = $bigDecimal->toString(); // "123.456"
$native = (string) $bigInteger; // "99999999999999999999"
Dependency Injection:
$this->app->bind(BigDecimal::class, fn() => BigDecimal::of('0'));
Form Requests:
BigDecimal:
use Brick\Math\Exception\NumberFormatException;
try {
$amount = BigDecimal::of($request->input('amount'));
} catch (NumberFormatException $e) {
return back()->withErrors(['amount' => 'Invalid format']);
}
Database Storage:
BigInteger/BigDecimal as strings in DB (e.g., BIGINT for hashes, TEXT for decimals).public function getAmountAttribute($value) {
return BigDecimal::of($value);
}
Testing:
BigDecimal for isolated tests:
$this->partialMock(BigDecimal::class, ['dividedBy'])
->method('dividedBy')
->willReturn(BigDecimal::of('1.5'));
Performance:
GMP/BCMath extensions for heavy computations (auto-selected by the library).BigDecimal instances.Floating-Point Traps:
float inputs: BigDecimal::of(0.1) throws NumberFormatException. Use strings or fromFloatExact():
// ❌ Fails
BigDecimal::of(0.1);
// ✅ Works
BigDecimal::of('0.1');
// or
BigDecimal::fromFloatExact(0.1);
Rounding Modes:
0.15.0: dividedBy() now requires explicit scale and RoundingMode. Old code:
// ❌ Breaks in 0.15+
$result = $decimal->dividedBy('3');
New code:
// ✅ Required
$result = $decimal->dividedBy('3', 2, RoundingMode::HalfUp);
BigInteger Modulo:
0.15.0: mod() now uses Euclidean modulo (always non-negative). Old code:
// ❌ May return negative
$modulus = BigInteger::of(-5);
$result = $number->mod($modulus);
New code:
// ✅ Throws InvalidArgumentException
$result = $number->mod($modulus); // Fails if $modulus ≤ 0
BigRational Simplification:
BigRational::of('4/6') returns 2/3 (no simplified() method).Serialization:
Bitwise Operations:
BigInteger: BigDecimal/BigRational lack bitwise methods.Exception Handling:
MathException broadly or specific exceptions (e.g., RoundingNecessaryException) for granular control.try-catch for user-facing errors (e.g., invalid input):
try {
$decimal = BigDecimal::of($userInput);
} catch (NumberFormatException $e) {
report($e);
return back()->withErrors(['input' => 'Invalid number']);
}
Precision Debugging:
$decimal->getScale(); // Returns current decimal places
$decimal->strippedOfTrailingZeros()->toString(); // Normalized string
Performance Bottlenecks:
GMP/BCMath:
// Force pure PHP (for testing)
putenv('BRICK_MATH_CALCULATOR=php');
Changelog Gotchas:
0.16.0: BigDecimal::getIntegralPart() now returns BigInteger (was int).0.17.0: BigDecimal::hasNonZeroFractionalPart() removed; use ! $number->getFractionalPart()->isZero().Custom Calculators:
Brick\Math\Calculator\CalculatorInterface for domain-specific optimizations (e.g., GPU acceleration).PHPStan Integration:
simPod/phpstan-brick-math for static analysis:
composer require --dev simpod/phpstan-brick-math
How can I help you explore Laravel packages today?