Yu Wu Hsien - Profile Picture
YU WU HSIEN

Just simple folk, with HTML, trying to make a living.

Laravel BCMath Cast: Integrating Precise Calculations into Eloquent Models

In my previous article, I demonstrated how to use PHP 8.4's BCMath Object API to solve floating-point precision issues and implemented a custom cast to integrate BCMath\Number.

However, every time I started a new project, I found myself copying and pasting the same cast code. This not only resulted in repetitive work but also increased maintenance costs.

Therefore, I packaged this cast into a small Laravel package: laravel-bcmath-cast.

Requirements

  • PHP 8.4+ (required for BCMath\Number class)
  • Laravel 11+

Installation

shell
composer require yuwuhsien/laravel-bcmath-cast

Usage

Add the AsDecimal cast to your Eloquent model:

php
use YuWuHsien\Decimal\Casts\AsDecimal;

class Product extends Model
{
    protected function casts(): array
    {
        return [
            'price' => AsDecimal::class,
            'cost' => AsDecimal::class,
            'tax_rate' => AsDecimal::class,
        ];
    }
}

These attributes will be automatically converted to BCMath\Number objects, allowing you to perform precise calculations directly using operators:

php
$product = Product::find(1);

// Attributes are now BCMath\Number instances
$product->price instanceof Number; // true

// Perform precise calculations directly with operators
$margin = $product->price - $product->cost;
$marginPercent = ($margin / $product->cost) * new Number('100');

// Calculate total with tax
$total = $product->price * (new Number('1') + $product->tax_rate);

Multiple Input Types Supported

php
use BcMath\Number;

// BCMath\Number object
$product->price = new Number('29.99');

// Numeric string (recommended for precision)
$product->price = '29.99';

// Integer
$product->price = 30;

// Float (works but triggers warning)
$product->price = 29.99;
// Warning: Float values may lose precision when converted to BCMath\Number.
// Use strings for exact decimal values (e.g., '19.99' instead of 19.99).

Why does using floats trigger a warning? Floats inherently have precision issues, which is exactly why we use BCMath:

php
// Float precision issue
var_dump(0.1 + 0.2); // float(0.30000000000000004)

// Even converting to BCMath\Number cannot recover the lost precision
$num = new Number(0.1 + 0.2);
var_dump($num->value); // "0.30000000000000004"

Therefore, if you need precise calculations, always use strings:

php
// Wrong: using float
$product->price = 19.99;

// Correct: using string
$product->price = '19.99';

Database Column Types

If your data requires precise calculations, database columns must use DECIMAL as the column type, not FLOAT:

php
Schema::create('products', function (Blueprint $table) {
    $table->decimal('price', 10, 2);  // Correct: precise decimal storage
    $table->decimal('cost', 10, 4);   // Correct: can specify different precision
    $table->float('amount');          // Wrong: loses precision
});

For more related explanations, please refer to my previous article.

Final Thoughts

This package originated from the implementation experience I shared in my previous article. The purpose of making it a standalone package is simple:

To allow projects requiring precise calculations to install and use it via Composer, without having to copy and paste code every time.

If you're also developing applications that require precise numerical calculations (finance, accounting, e-commerce, inventory management, etc.), try this package in your projects:

shell
composer require yuwuhsien/laravel-bcmath-cast
© 2025 Yu Wu Hsien.