PHPackages                             fab2s/math - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. fab2s/math

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

fab2s/math
==========

A Base10 high precision math helper

3.0.0(4mo ago)3306.9k↓45.3%12MITPHPPHP ^8.1CI failing

Since Aug 10Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/fab2s/Math)[ Packagist](https://packagist.org/packages/fab2s/math)[ RSS](/packages/fab2s-math/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (4)Dependencies (7)Versions (8)Used By (2)

Math
====

[](#math)

[![CI](https://github.com/fab2s/Math/actions/workflows/ci.yml/badge.svg)](https://github.com/fab2s/Math/actions/workflows/ci.yml)[![QA](https://github.com/fab2s/Math/actions/workflows/qa.yml/badge.svg)](https://github.com/fab2s/Math/actions/workflows/qa.yml)[![codecov](https://camo.githubusercontent.com/48dd98292e2785fcf9c01c7d4d404c9e9fcbcc39bfc50029494614bbeb68f876/68747470733a2f2f636f6465636f762e696f2f67682f66616232732f4d6174682f67726170682f62616467652e7376673f746f6b656e3d364a44333343514c4533)](https://codecov.io/gh/fab2s/Math)[![Latest Stable Version](https://camo.githubusercontent.com/42c48c66e6f2e4ad19c39e89667f4e322cfa8706c46327407ff3fe2e79a1ba52/68747470733a2f2f706f7365722e707567782e6f72672f66616232732f6d6174682f762f737461626c65)](https://packagist.org/packages/fab2s/math)[![Total Downloads](https://camo.githubusercontent.com/db80e3c8bf5832e09a8ade6487c165005060d2d62e21c001aaa57872fe7f0c09/68747470733a2f2f706f7365722e707567782e6f72672f66616232732f6d6174682f646f776e6c6f616473)](https://packagist.org/packages/fab2s/math)[![Monthly Downloads](https://camo.githubusercontent.com/a96b941f653c709d800b2a61ce39751e0ec69e3ddf12e22f072c534f88c85ac4/68747470733a2f2f706f7365722e707567782e6f72672f66616232732f6d6174682f642f6d6f6e74686c79)](https://packagist.org/packages/fab2s/math)[![PHPStan](https://camo.githubusercontent.com/83dd3d35cebed0eab9ee97ff1a5849c1344cda6a8ee9cac2cda20f5aa55b67bd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230392d627269676874677265656e2e7376673f7374796c653d666c6174)](https://phpstan.org)[![PRs Welcome](https://camo.githubusercontent.com/7d9ed3c8f22eceb1711573169b1390cc0b1194467340dc815205060c162b5309/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e7376673f7374796c653d666c6174)](http://makeapullrequest.com)[![License](https://camo.githubusercontent.com/fdf5e2c1c6a9326e5c09490a962f317249a26093c60b57c5992fc86e155497be/68747470733a2f2f706f7365722e707567782e6f72672f66616232732f6d6174682f6c6963656e7365)](https://packagist.org/packages/fab2s/math)

A fluent, high-precision arithmetic library for PHP built on [bcmath](https://php.net/bcmath). Designed for financial calculations, scientific computing, and anywhere floating-point errors are unacceptable.

The Problem
-----------

[](#the-problem)

Floating-point arithmetic has well-known precision limitations:

```
var_dump((0.1 + 0.7) == 0.8);   // false
var_dump((1.4 - 1) * 100);      // 39.99999999999999
var_dump(0.7 + 0.1 - 0.8);      // -1.1102230246251565E-16
```

> `bcmath` supports numbers of any size and precision up to 2,147,483,647 decimals, represented as strings.

Installation
------------

[](#installation)

```
composer require fab2s/math
```

### Requirements

[](#requirements)

- PHP 8.1+
- ext-bcmath (required)
- ext-gmp (optional, faster base conversions, mod, pow and powMod)

Features
--------

[](#features)

### Fluent API

[](#fluent-api)

Chain operations naturally with variadic argument support:

```
use fab2s\Math\Math;

$result = Math::number('100')
    ->add('10', '20', '30')   // 160
    ->mul('2')                 // 320
    ->div('4')                 // 80
    ->sub('38');               // 42

echo $result; // '42'
```

`Math` is **immutable** — every operation returns a new instance, leaving the original unchanged:

```
$a = Math::number('100');
$b = $a->add('50');   // $a is still '100', $b is '150'
$c = $b->mul('2');    // $b is still '150', $c is '300'
```

The overhead is a single `clone` per operation (two properties: a string and an int).

### Mutable Variant

[](#mutable-variant)

For performance-sensitive hot loops, `MathMutable` modifies the instance in place:

```
use fab2s\Math\MathMutable;

$sum = MathMutable::number('0');
for ($i = 0; $i < 1000; $i++) {
    $sum->add($i . '.99'); // modifies $sum in place, no clone
}
```

`MathMutable` extends `Math`, so it is accepted anywhere `Math` is type-hinted.

### Strict Validation

[](#strict-validation)

Math rejects ambiguous inputs that bcmath would silently convert to `0`:

```
// Valid
Math::number('42');
Math::number('-0.005');
Math::number('.5');

// Throws exception
Math::number('1E12');   // Exponential notation
Math::number('3,14');   // Comma separator
Math::number('$100');   // Currency symbols
```

### Full Arithmetic Operations

[](#full-arithmetic-operations)

```
$n = Math::number('100');

// Basic
$n->add(...$nums);   // Addition
$n->sub(...$nums);   // Subtraction
$n->mul(...$nums);   // Multiplication
$n->div(...$nums);   // Division

// Advanced
$n->sqrt();          // Square root
$n->pow('2');        // Power
$n->mod('7');        // Modulo
$n->powMod($e, $m);  // Modular exponentiation
$n->abs();           // Absolute value
$n->negate();        // Flip sign

// Division
$n->quotientAndRemainder('7');       // [$quotient, $remainder]

// Rounding
$n->round(2);        // Round to 2 decimals
$n->floor();         // Round down
$n->ceil();          // Round up

// Limits
$n->min('50', '200');     // 50
$n->max('50', '200');     // 200
$n->clamp('10', '90');    // Clip between bounds
```

### Comparisons &amp; Inspection

[](#comparisons--inspection)

```
$n = Math::number('42');

$n->eq('42');    // true  — equal
$n->gt('40');    // true  — greater than
$n->gte('42');   // true  — greater than or equal
$n->lt('50');    // true  — less than
$n->lte('42');   // true  — less than or equal

$n->isZero();      // false
$n->isPositive();  // true
$n->isNegative();  // false
$n->isEven();      // true
$n->isOdd();       // false

$n = Math::number('42.99');
$n->getScale();          // 2
$n->getIntegralPart();   // '42'
$n->getFractionalPart(); // '99'
```

### Base Conversion (2-62)

[](#base-conversion-2-62)

Uses GMP when available for faster conversions:

```
// From base X to base 10
Math::fromBase('LZ', 62);      // '1337'
Math::fromBase('101010', 2);   // '42'
Math::fromBase('ff', 16);      // '255' (case-insensitive for bases toBase(62);  // 'LZ'
Math::number('42')->toBase(2);     // '101010'
Math::number('255')->toBase(16);   // 'ff'

// Negative numbers preserve their sign
Math::number('-42')->toBase(16);     // '-2a'
Math::fromBase('-LZ', 62);          // '-1337'
```

### Formatting

[](#formatting)

Formatting does not mutate the internal number:

```
$n = Math::number('1234567.891');

echo $n->format(2);             // '1234567.89'
echo $n->format(2, ',', ' ');   // '1 234 567,89'
echo $n;                        // '1234567.891' (unchanged)
```

### Precision Control

[](#precision-control)

Default precision is 9 decimal places. Control it globally or per-instance:

```
// Global (affects new instances)
Math::setGlobalPrecision(18);

// Per-instance
$n = Math::number('100')->setPrecision(4);
echo $n->div('3'); // '33.3333'
```

> Precision is not handled via `bcscale()` to avoid global state issues in long-running processes.

### Normalized Output

[](#normalized-output)

Results are automatically normalized for accurate comparisons:

```
echo Math::number('0000042.000'); // '42'
echo Math::number('-0');          // '0'
echo Math::number('+.500');       // '0.5'

// Raw access when needed
Math::number('0042.00')->getNumber(); // '0042.00'
```

### Instance Reuse

[](#instance-reuse)

Pass Math instances directly to avoid re-validation:

```
$tax = Math::number('0.20');
$price = Math::number('99.99');

$total = $price->add($price->mul($tax));
```

Laravel Integration
-------------------

[](#laravel-integration)

Cast Eloquent model attributes to Math instances:

```
use fab2s\Math\Laravel\MathCast;

class Order extends Model
{
    protected $casts = [
        'total'    => MathCast::class,
        'discount' => MathCast::class . ':nullable',
    ];
}

$order = new Order;
$order->total = '99.99';
$order->total->mul('1.2')->format(2); // '119.99'

$order->discount = null;  // OK (nullable)
$order->total = null;     // Throws NotNullableException
```

### Mutable Cast

[](#mutable-cast)

Use `MathMutableCast` to get `MathMutable` instances instead of immutable `Math`:

```
use fab2s\Math\Laravel\MathCast;
use fab2s\Math\Laravel\MathMutableCast;

class Order extends Model
{
    protected $casts = [
        'total'    => MathMutableCast::class,
        'discount' => MathMutableCast::class . ':nullable',
        'tax'      => MathCast::class,              // immutable (default)
    ];
}

$order = new Order;
$order->total = '99.99';
$order->total->add('10'); // modifies in place
```

Using separate cast classes enables proper static type resolution — Larastan/PHPStan will resolve `MathCast` properties to `Math` and `MathMutableCast` properties to `MathMutable`.

### Upgrading from v2

[](#upgrading-from-v2)

In v2, `Math` was mutable, so `MathCast` attributes behaved as mutable values. In v3, `Math` is immutable by default — existing code that mutates cast attributes in place will silently lose changes:

```
// v2: works — Math was mutable
// v3: $order->total is unchanged — Math is now immutable
$order->total->add('10');
```

To restore the previous behavior, switch to `MathMutableCast`:

```
use fab2s\Math\Laravel\MathMutableCast;

protected $casts = [
    'total'    => MathMutableCast::class,
    'discount' => MathMutableCast::class . ':nullable',
];
```

API Reference
-------------

[](#api-reference)

### Factory Methods

[](#factory-methods)

MethodDescription`Math::number($n)`Create immutable instance`Math::make($n)`Alias for `number()``Math::fromBase($n, $base)`Create from base 2-62`MathMutable::number($n)`Create mutable instance`MathMutable::make($n)`Alias for `number()``MathMutable::fromBase($n, $base)`Create mutable from base 2-62### Arithmetic

[](#arithmetic)

MethodDescription`add(...$n)`Addition`sub(...$n)`Subtraction`mul(...$n)`Multiplication`div(...$n)`Division`quotientAndRemainder($n)`Returns `[$quotient, $remainder]``mod($n)`Modulo`pow($n)`Power`powMod($exp, $mod)`Modular exponentiation`sqrt()`Square root`abs()`Absolute value`negate()`Flip sign`clamp($min, $max)`Clip between bounds### Rounding

[](#rounding)

MethodDescription`round($precision)`Round to precision`floor()`Round down`ceil()`Round up### Comparison &amp; Inspection

[](#comparison--inspection)

MethodDescription`eq($n)`Equal`gt($n)`Greater than`gte($n)`Greater than or equal`lt($n)`Less than`lte($n)`Less than or equal`min(...$n)`Minimum value`max(...$n)`Maximum value`isZero()`Check if zero`isPositive()`Check if positive`isNegative()`Check if negative`isEven()`Check if even integer`isOdd()`Check if odd integer### Conversion &amp; Output

[](#conversion--output)

MethodDescription`toBase($base)`Convert to base 2-62`format($dec, $point, $sep)`Format with separators`getNumber()`Get raw (non-normalized) number`getScale()`Number of decimal places`getIntegralPart()`Part before the decimal point`getFractionalPart()`Part after the decimal point`(string)`Get normalized number### Precision

[](#precision)

MethodDescription`setPrecision($p)`Set instance precision`getPrecision()`Get instance precision`Math::setGlobalPrecision($p)`Set default for new instances`Math::getGlobalPrecision()`Get global precisionBenchmarks
----------

[](#benchmarks)

Compared against [brick/math](https://github.com/brick/math) (PHP 8.4, opcache off, GMP enabled). The **bold** value is the faster one in each row, and *Factor* shows how many times faster it is.

Operationfab2s/mathbrick/mathFactorinstantiate int**0.261μs (±4.0%)**0.301μs (±8.9%)1.15xinstantiate string**0.244μs (±36.6%)**0.678μs (±4.5%)2.78xadd**0.632μs (±9.7%)**2.278μs (±3.0%)3.60xadd variadic**1.406μs (±5.6%)**6.653μs (±1.3%)4.73xsub**0.612μs (±1.7%)**2.325μs (±4.8%)3.80xmul**0.665μs (±2.5%)**2.183μs (±4.9%)3.28xdiv**0.762μs (±4.1%)**4.664μs (±3.6%)6.12xpow**0.986μs (±47.0%)**1.416μs (±45.5%)1.44xmod**0.851μs (±2.3%)**2.851μs (±42.2%)3.35xsqrt**2.160μs (±3.6%)**4.536μs (±11.3%)2.10xabs**0.344μs (±4.0%)**0.919μs (±35.8%)2.67xnegate**0.379μs (±10.5%)**1.036μs (±93.7%)2.73xclamp**0.956μs (±64.5%)**4.325μs (±32.5%)4.53xquotient &amp; remainder**0.894μs (±10.7%)**2.878μs (±4.6%)3.22xinspection**1.943μs (±5.7%)**4.672μs (±3.7%)2.40xround**0.596μs (±31.8%)**3.495μs (±10.2%)5.86xceil**0.528μs (±8.1%)**2.965μs (±39.6%)5.62xfloor**0.469μs (±6.2%)**2.504μs (±4.0%)5.34xcomparisons**1.400μs (±7.5%)**6.171μs (±4.7%)4.41xto string**0.529μs (±6.6%)**0.789μs (±3.4%)1.49xchained workflow**1.810μs (±3.2%)**8.519μs (±2.0%)4.71xlarge number ops**1.792μs (±5.9%)**8.273μs (±1.8%)4.62xaccumulate 100 additions**41.182μs (±3.0%)**147.875μs (±11.8%)3.59xbase convert to 62**1.162μs (±23.8%)**6.888μs (±5.6%)5.93xbase convert to 161.081μs (±15.3%)**0.965μs (±7.6%)**0.89xinteger mul**0.937μs (±11.6%)**1.873μs (±5.3%)2.00xinteger powmod**1.263μs (±10.0%)**2.810μs (±7.9%)2.22xcreate 1000 instances**301.794μs (±4.2%)**731.200μs (±2.6%)2.42xAll operations above use immutable `Math` (the default). fab2s/math wins every operation except base-16 conversion, where brick/math delegates to GMP's native hex output. The speed advantage comes from keeping bcmath's C-level string arithmetic as the hot path for decimal operations, while brick/math pays for an extra object-wrapping layer on top of GMP. Integer-only operations (`mod`, `pow`, `powMod`, base conversion) use GMP directly when the extension is available, combining the best of both backends. Realistic workflows like chained calculations or 100-iteration accumulations show a consistent 3-5x advantage, with immutability costing only a lightweight `clone` per operation (two properties: a string and an int).

`MathMutable` eliminates the clone overhead entirely for hot loops:

OperationMathMutableMath (immutable)brick/mathchained workflow**1.964μs (±8.5%)**2.294μs (±5.0%)14.149μs (±3.9%)accumulate 100**38.086μs (±2.0%)**41.339μs (±2.5%)147.063μs (±0.4%)branch2.795μs (±4.0%)**2.580μs (±3.3%)**12.885μs (±20.7%)Run benchmarks yourself:

```
composer bench                              # ASCII table
composer bench-md                           # Markdown table
composer bench-md -- --group=integer        # Filter by group
```

Compatibility
-------------

[](#compatibility)

PHPLaravel8.1108.210, 11, 128.310, 11, 128.410, 11, 12Related
-------

[](#related)

`Math` is also included in [OpinHelpers](https://github.com/fab2s/OpinHelpers), a collection of utilities for common PHP challenges.

Contributing
------------

[](#contributing)

Contributions are welcome. Please open issues and submit pull requests.

```
# fix code style
composer fix

# run tests
composer test

# run tests with coverage
composer cov

# static analysis (src, level 9)
composer stan

# static analysis (tests, level 5)
composer stan-tests
```

License
-------

[](#license)

Math is open-source software licensed under the [MIT license](https://opensource.org/licenses/MIT).

###  Health Score

54

—

FairBetter than 97% of packages

Maintenance78

Regular maintenance activity

Popularity38

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~475 days

Recently: every ~425 days

Total

6

Last Release

121d ago

Major Versions

1.x-dev → v2.x-dev2024-04-23

2.0.0 → 3.0.02026-02-08

PHP version history (2 changes)1.0.0PHP &gt;=7.1

v2.x-devPHP ^8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/7323989?v=4)[fab2s](/maintainers/fab2s)[@fab2s](https://github.com/fab2s)

---

Top Contributors

[![fab2s](https://avatars.githubusercontent.com/u/7323989?v=4)](https://github.com/fab2s "fab2s (18 commits)")

---

Tags

base10bcmathdecimalhelperhigh-precisionmathphpphplaraveldecimalmathSimplebcmathbase10HighPrecision

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/fab2s-math/health.svg)

```
[![Health](https://phpackages.com/badges/fab2s-math/health.svg)](https://phpackages.com/packages/fab2s-math)
```

###  Alternatives

[krowinski/bcmath-extended

Extends php BCMath lib for missing functions like floor, ceil, round, abs, min, max, rand for big numbers. Also wraps existing BCMath functions. (more http://php.net/manual/en/book.bc.php) Supports scientific notations

801.1M22](/packages/krowinski-bcmath-extended)[prestashop/decimal

Object-oriented wrapper/shim for BC Math PHP extension. Allows for arbitrary-precision math operations.

178.7M7](/packages/prestashop-decimal)[amranidev/laracombee

Recommendation system for laravel

11537.9k1](/packages/amranidev-laracombee)[yieldstudio/tailwind-merge-php

Merge Tailwind CSS classes without style conflicts

4974.6k1](/packages/yieldstudio-tailwind-merge-php)[wujunze/money-wrapper

MoneyPHP Wrapper

113.8k](/packages/wujunze-money-wrapper)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
