PHPackages                             jimeneztdavid/scaled-int - 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. jimeneztdavid/scaled-int

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

jimeneztdavid/scaled-int
========================

A value object for scaled integers (e.g. money cents) with safe arithmetic and configurable rounding.

1.2.0(1mo ago)1341MITPHPPHP &gt;=8.3

Since Jan 26Pushed 1mo agoCompare

[ Source](https://github.com/jimeneztdavid/scaled-int)[ Packagist](https://packagist.org/packages/jimeneztdavid/scaled-int)[ RSS](/packages/jimeneztdavid-scaled-int/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (2)Versions (4)Used By (1)

ScaledInt
=========

[](#scaledint)

Why this package exists
-----------------------

[](#why-this-package-exists)

Working with **money, prices, weights, percentages, or any decimal-based value** using floating-point numbers (`float`) is dangerous. Rounding errors, precision loss, and unexpected comparisons are common problems in real-world applications.

**ScaledInt** solves this by:

- Storing values internally as **integers only**
- Applying a fixed **scale (power of 10)** to represent decimals
- Providing **safe arithmetic**, comparisons, and rounding
- Avoiding floating-point math entirely

This makes it ideal for:

- Money and prices
- Taxes (IVA / VAT)
- Percentages and discounts
- Measurements (kg, grams, meters)
- Any domain where precision matters

---

Core concept
------------

[](#core-concept)

A `ScaledInt` stores:

- **minor** → integer value (scaled)
- **scale** → power of 10 (10, 100, 1000, etc.)

Example with scale `100`:

Human valueStored minor`10.25``1025``5.00``500``-3.50``-350`---

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

[](#installation)

```
composer require jimeneztdavid/scaled-int
```

---

Creating values
---------------

[](#creating-values)

### From a major (human) value

[](#from-a-major-human-value)

```
use Jimeneztdavid\ScaledInt\ScaledInt;

$price = ScaledInt::fromMajor('10.25'); // scale = 100 by default
```

### From a minor (integer) value

[](#from-a-minor-integer-value)

```
$price = ScaledInt::fromMinor(1025); // represents 10.25
```

### Using a custom scale

[](#using-a-custom-scale)

```
$weight = ScaledInt::fromMajor('1.234', 1000); // 3 decimals
```

Scale must be a power of 10 (`10`, `100`, `1000`, ...)

---

Reading values
--------------

[](#reading-values)

### Get minor value

[](#get-minor-value)

```
$price->minor(); // 1025
```

### Get scale

[](#get-scale)

```
$price->scale(); // 100
```

### Convert back to string

[](#convert-back-to-string)

```
$price->toMajorString(); // "10.25"
```

```
echo $price; // "10.25"
```

---

Comparisons
-----------

[](#comparisons)

All comparisons require **the same scale**.

```
$a = ScaledInt::fromMajor('10.00');
$b = ScaledInt::fromMajor('12.50');

$a->lessThan($b);     // true
$b->greaterThan($a); // true
$a->equalTo($b);     // false
```

compareTo()
-----------

[](#compareto)

Use `compareTo()` when you want a single method that tells you the ordering between two `ScaledInt` values.

- Returns **-1** if this value is **less than** the other
- Returns 0 if both values are **equal**
- Returns **1** if this value is **greater than** the other

Both numbers must have the same scale, otherwise an `InvalidArgumentException` is thrown.

### Example

[](#example)

```
use Jimeneztdavid\ScaledInt\ScaledInt;

$a = ScaledInt::fromMajor('10.25'); // 10.25
$b = ScaledInt::fromMajor('10.30'); // 10.30
$c = ScaledInt::fromMajor('10.25'); // 10.25

$a->compareTo($b); // -1  (a < b)
$b->compareTo($a); //  1  (b > a)
$a->compareTo($c); //  0  (a == c)
```

min() and max()
---------------

[](#min-and-max)

Use `min()` to get the smaller value and `max()` to get the larger value.

```
use Jimeneztdavid\ScaledInt\ScaledInt;

$a = ScaledInt::fromMajor('10.25');
$b = ScaledInt::fromMajor('10.30');

$a->min($b); // 10.25
$a->max($b); // 10.30
```

Both values must have the same scale.

between()
---------

[](#between)

Use `between()` to check whether a value is inside an inclusive range.

```
use Jimeneztdavid\ScaledInt\ScaledInt;

$value = ScaledInt::fromMajor('15.00');
$min = ScaledInt::fromMajor('10.00');
$max = ScaledInt::fromMajor('20.00');

$value->between($min, $max); // true
```

Both bounds and the value must have the same scale.

---

Arithmetic operations
---------------------

[](#arithmetic-operations)

### Addition

[](#addition)

```
$total = $a->add($b);
```

### Subtraction

[](#subtraction)

```
$diff = $b->subtract($a);
```

### Multiply by integer

[](#multiply-by-integer)

```
$double = $price->multiplyByInt(2);
```

### Divide by integer (exact)

[](#divide-by-integer-exact)

```
$half = $price->divideByIntExact(2);
```

Throws if the division is not exact.

---

Division with rounding
----------------------

[](#division-with-rounding)

```
use Jimeneztdavid\ScaledInt\RoundingMode;

$result = $price->divideByInt(3, RoundingMode::HALF_UP);
```

Supported modes:

- `UP`
- `DOWN`
- `HALF_UP`
- `HALF_EVEN`

---

Percentages
-----------

[](#percentages)

```
$price = ScaledInt::fromMajor('100.00');

$iva = $price->percentOf(19, RoundingMode::HALF_UP); // 19.00
```

---

Common scenarios
----------------

[](#common-scenarios)

### Calculate IVA (VAT)

[](#calculate-iva-vat)

```
$price = ScaledInt::fromMajor('100.00');
$iva   = $price->percentOf(19, RoundingMode::HALF_UP);

$total = $price->add($iva); // 119.00
```

---

### Extract IVA from a final price

[](#extract-iva-from-a-final-price)

IVA included price formula:

```
base = total / (1 + IVA)

```

Example with 19% IVA:

```
$total = ScaledInt::fromMajor('119.00');

$base = $total
    ->multiplyByInt(100)
    ->divideByInt(119, RoundingMode::HALF_EVEN);

$iva = $total->subtract($base);
```

---

### Discounts

[](#discounts)

```
$price = ScaledInt::fromMajor('200.00');

$discount = $price->percentOf(15, RoundingMode::HALF_UP);
$final    = $price->subtract($discount);
```

---

### Measurements (non-money)

[](#measurements-non-money)

```
$weight = ScaledInt::fromMajor('2.750', 1000); // kg
$double = $weight->multiplyByInt(2);           // 5.500 kg
```

---

Why not floats?
---------------

[](#why-not-floats)

```
0.1 + 0.2 !== 0.3
```

```
ScaledInt::fromMajor('0.10')->add(
    ScaledInt::fromMajor('0.20')
)->toMajorString(); // "0.30"
```

---

Design principles
-----------------

[](#design-principles)

- Immutable objects
- Integer-only math
- Explicit rounding
- Overflow-safe operations
- Scale consistency enforced

---

When to use ScaledInt
---------------------

[](#when-to-use-scaledint)

Financial calculations
Taxes and percentages
Measurements
Precise comparisons

Scientific floating-point math
Values requiring arbitrary precision decimals

---

Float vs ScaledInt
------------------

[](#float-vs-scaledint)

Aspect`float``ScaledInt`PrecisionImprecise (binary rounding errors)Exact (integer math)Internal representationIEEE 754 binary floating pointInteger + fixed scale`0.1 + 0.2``0.30000000000000004``"0.30"`Equality comparisonUnreliableSafe and deterministicRounding controlImplicit and inconsistentExplicit (UP, DOWN, HALF\_UP, HALF\_EVEN)Overflow detectionSilentExplicit exceptionsCurrency safetyDangerousDesigned for moneyPercentage calculationsError-proneDeterministicComparisons (`> < ==`)RiskyGuaranteed correctnessDomain intentGeneric numericExplicit domain modelingProduction suitabilityNeeds extra careSafe by defaultLicense
-------

[](#license)

MIT

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance93

Actively maintained with recent releases

Popularity11

Limited adoption so far

Community5

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

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 ~61 days

Total

3

Last Release

36d ago

PHP version history (2 changes)v1.0.0PHP &gt;=8.1

1.2.0PHP &gt;=8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/26b7a75885ffcbf6e7e2b66ca5d37fa0b639ca36bb6654cf60b2c6255708928e?d=identicon)[jimeneztdavid](/maintainers/jimeneztdavid)

---

Tags

phpmoneyValue Objectdecimalroundingscaled-integer

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jimeneztdavid-scaled-int/health.svg)

```
[![Health](https://phpackages.com/badges/jimeneztdavid-scaled-int/health.svg)](https://phpackages.com/packages/jimeneztdavid-scaled-int)
```

###  Alternatives

[moneyphp/money

PHP implementation of Fowler's Money pattern

4.8k91.5M525](/packages/moneyphp-money)[ulabox/money

Yet another PHP implementation of the Money value object using BCMath

79242.9k](/packages/ulabox-money)[rtlopez/decimal

An object oriented immutable arbitrary-precision arithmetic library for PHP

27274.7k2](/packages/rtlopez-decimal)[adsmurai/currency

A small library to handle currencies and money values

4443.1k](/packages/adsmurai-currency)[ramazancetinkaya/byte-formatter

A modern PHP library for formatting and parsing byte values with precision and flexibility.

145.0k](/packages/ramazancetinkaya-byte-formatter)[fruitcake/php-decimal

Decimal class for PHP

162.5k](/packages/fruitcake-php-decimal)

PHPackages © 2026

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