oriolsegura/laravel-decimal

Value Object to handle decimals in Laravel without losing precision and directly from Eloquent models.

Maintainers

Package info

github.com/oriolsegura/laravel-decimal

pkg:composer/oriolsegura/laravel-decimal

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 4

Open Issues: 0

v0.6.0 2026-02-08 13:50 UTC

This package is auto-updated.

Last update: 2026-03-08 13:56:26 UTC


README

Latest Version on Packagist Tests Total Downloads License PHP Version

A lightweight, immutable Value Object to handle decimals in Laravel without losing precision.

It uses bcmath internally to ensure mathematical correctness where floats fail.

🚀 Why use this package?

Designed for simplicity and immediate productivity. If you need to handle money or precise numbers in Laravel but don't want the overhead of heavy financial libraries or complex configurations, this is for you.

  • Plug & Play: Zero configuration. Works out of the box.
  • Laravel Native: Built with Eloquent casting in mind.
  • Lightweight: No heavy dependencies. Just a wrapper around bcmath.

Ideal for e-commerce, invoices, scientific data, and any scenario where 0.1 + 0.2 must equal 0.3.

⚠️ The Problem with Floats

Floating-point arithmetic is not precise because IEEE 754 standard cannot represent all decimal fractions exactly.

An example of this issue:

echo sprintf("%.17f", 0.1 + 0.2); // 0.30000000000000004 ❌

echo var_dump(0.3 === (0.1 + 0.2)); // bool(false) ❌

🛠️ Requirements

  • PHP 8.2+
  • Laravel 11.0+ / 12.0+
  • ext-bcmath

Installation

composer require oriolsegura/laravel-decimal

Eloquent Casting

This package shines when used with Eloquent models. You can store values as precise decimals (or strings) in your database and work with Decimal objects automatically in your code.

  1. Define the cast in your Model:
use Illuminate\Database\Eloquent\Model;
use OriolSegura\Decimal\Decimal;

class Product extends Model
{
    protected $casts = [
        'price' => Decimal::class, // <--- Auto-casting
    ];
}
  1. Enjoy seamless precision:
$product = Product::create([
    'price' => '19.99',
]);

// You can operate directly on the attribute
$product->price = $product->price->add('5.50');
$product->save();

Usage API

Creation

You can create a Decimal from a string, integer or another Decimal.

$a = Decimal::from('10.50');
$b = Decimal::from(10);

Arithmetic

Since the object is immutable, operations always return a new instance.

$val = Decimal::from('10');

// Chaining
$result = $val->plus(5)->minus(2)->times(2); // (10 + 5 - 2) * 2 = 26

Supported methods

These are the implemented methods for arithmetic operations:

  • plus(self|int|string $other) (alias: add, sum)
  • minus(self|int|string $other) (alias: take, subtract)
  • times(self|int|string $other) (alias: mul, multiply)
  • dividedBy(self|int|string $other, int|null $scale = null) (alias: div)
  • mod(self|int|string $other) (alias: modulo, remainder)
  • abs()
  • negate() (aliases: neg)
  • inverse() (aliases: inv, reciprocal)

And these are the implemented methods for comparisons:

  • eq(self|int|string $other) (alias: equals)
  • ne(self|int|string $other) (alias: notEquals, diff)
  • gt(self|int|string $other) (alias: greaterThan)
  • gte(self|int|string $other) (alias: greaterThanOrEqual)
  • lt(self|int|string $other) (alias: lessThan)
  • lte(self|int|string $other) (alias: lessThanOrEqual)
  • isZero()
  • isPositive()
  • isNegative()
  • isStrictlyPositive()
  • isStrictlyNegative()
  • min(self|int|string $other, self|int|string ...$values)
  • max(self|int|string $other, self|int|string ...$values)

Division & Rounding

By default, division uses an automatic scale equal to the maximum of the two operands scales, ensuring this is also at least 12 decimal places to ensure precision. But you can also provide a $scale parameter to specify the number of decimal places in the result.

Currently, this library only supports Half-Up Rounding for division.

// Automatic scale (truncating logic for infinite fractions)
echo Decimal::from(1)->div(3); // "0.333333333333"

// Explicit scale (Rounds Half-Up)
echo Decimal::from(2)->div(3, scale: 2); // "0.67"

License

This package is open-sourced software licensed under the MIT license.