Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [[v0.2.2](https://github.com/The-FireHub-Project/Runtime/compare/v0.2.1...v0.2.2)] – 2026-08-31

### Added
* Improved `mod` method for `DecimalEngine` by @dieselxxx

## [[v0.2.1](https://github.com/The-FireHub-Project/Runtime/compare/v0.2.0...v0.2.1)] – 2026-08-31

### Added
Expand Down
113 changes: 71 additions & 42 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Math/Decimal/Divide.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ trait Divide {
* @param non-empty-string $right <p>
* The divisor.
* </p>
* @param positive-int $scale [optional] <p>
* @param non-negative-int $scale [optional] <p>
* The number of decimal places to calculate.
* </p>
*
Expand Down
66 changes: 66 additions & 0 deletions src/Math/Decimal/Mod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php declare(strict_types = 1);

/**
* This file is part of the FireHub Project ecosystem
*
* @author Danijel Galić <danijel.galic@outlook.com>
* @copyright 2026-present The FireHub Project - All rights reserved
* @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
*
* @php-version >=7.4
* @package Runtime
*/

namespace FireHub\Runtime\Math\Decimal;

use DivisionByZeroError;

/**
* ### Decimal Number Modulo
* @since 1.0.0
*/
trait Mod {

/**
* ### Calculates the remainder of a decimal division
*
* The remainder follows truncation-toward-zero semantics. Its sign is the same as the dividend.
* @since 1.0.0
*
* @uses \FireHub\Runtime\Math\DecimalEngine::normalize() To normalize the decimal values.
* @uses \FireHub\Runtime\Math\DecimalEngine::divide() To calculate the truncated quotient.
* @uses \FireHub\Runtime\Math\DecimalEngine::multiply() To calculate the product of the quotient and divisor.
* @uses \FireHub\Runtime\Math\DecimalEngine::subtract() To calculate the remainder.
*
* @param non-empty-string $left <p>
* The dividend.
* </p>
* @param non-empty-string $right <p>
* The divisor.
* </p>
*
* @throws \FireHub\Runtime\Exception\InvalidDecimalNumberException If either decimal value is invalid.
* @throws \DivisionByZeroError If the divisor is zero.
*
* @return numeric-string The remainder of the division.
*/
public static function mod (string $left, string $right):string {

[, $right_integer, $right_fraction] = self::normalize($right);

if ($right_integer === '0' && $right_fraction === '')
throw new DivisionByZeroError('Modulo by zero.');

[, $left_integer, $left_fraction] = self::normalize($left);

if ($left_integer === '0' && $left_fraction === '') return '0';

$quotient = self::divide($left, $right, 0);
$product = self::multiply($quotient, $right);

/** @var numeric-string */
return self::subtract($left, $product);

}

}
4 changes: 2 additions & 2 deletions src/Math/DecimalEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use FireHub\Core\Boundary\Runtime\NativeRuntime;
use FireHub\Core\Meta\Enum\Side;
use FireHub\Runtime\Math\Decimal\ {
Arithmetic, Divide, Multiply, Round
Arithmetic, Divide, Mod, Multiply, Round
};
use FireHub\Runtime;
use FireHub\Runtime\Exception\InvalidDecimalNumberException;
Expand All @@ -37,7 +37,7 @@ final class DecimalEngine extends NativeRuntime {
* ### Implements operations
* @since 1.0.0
*/
use Arithmetic, Divide, Multiply, Round;
use Arithmetic, Divide, Mod, Multiply, Round;

/**
* ### Compares two positive decimal values
Expand Down
56 changes: 56 additions & 0 deletions tests/Unit/Math/DecimalEngineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -523,4 +523,60 @@ public function testPositiveInfinity (string $expected, string $value, int $prec

}

/**
* @since 1.0.0
*
* @param string $expected
* @param non-empty-string $left
* @param non-empty-string $right
*
* @throws \FireHub\Runtime\Exception\InvalidDecimalNumberException
* @throws \DivisionByZeroError
*
* @return void
*/
#[TestWith(['1', '10', '3'])]
#[TestWith(['2', '11', '3'])]
#[TestWith(['0', '12', '3'])]
#[TestWith(['1', '13', '3'])]
#[TestWith(['2', '14', '3'])]
#[TestWith(['0', '0', '3'])]
#[TestWith(['0', '3', '3'])]
#[TestWith(['1', '4', '3'])]
#[TestWith(['2', '5', '3'])]
#[TestWith(['-1', '-10', '3'])]
#[TestWith(['-2', '-11', '3'])]
#[TestWith(['0', '-12', '3'])]
#[TestWith(['-1', '-13', '3'])]
#[TestWith(['1', '10', '-3'])]
#[TestWith(['2', '11', '-3'])]
#[TestWith(['0', '12', '-3'])]
#[TestWith(['-1', '-10', '-3'])]
#[TestWith(['-2', '-11', '-3'])]
#[TestWith(['0', '-12', '-3'])]
#[TestWith(['0.34', '12.34', '4'])]
#[TestWith(['0.34', '12.34', '4.0'])]
#[TestWith(['1.34', '13.34', '4'])]
#[TestWith(['0.5', '10.5', '5'])]
#[TestWith(['0.25', '10.25', '5'])]
#[TestWith(['0.01', '10.01', '5'])]
#[TestWith(['2.23', '12.23', '2.5'])]
#[TestWith(['0.1', '1.1', '0.5'])]
#[TestWith(['0', '1.5', '0.5'])]
#[TestWith(['0.34', '12.34', '4.0'])]
#[TestWith(['1.34', '13.34', '4.0'])]
#[TestWith(['0.02', '1.02', '0.5'])]
#[TestWith(['0.25', '1.25', '0.5'])]
#[TestWith(['1', '100000000000000000000000000000000000001', '100000000000000000000000000000000000000'])]
#[TestWith(['999999999999999999', '1999999999999999999', '1000000000000000000'])]
#[TestWith(['0', '100000000000000000000000000000000000000', '100000000000000000000000000000000000000'])]
#[TestWith(['1', '0000010', '0000003'])]
#[TestWith(['0.5', '0010.5', '5'])]
#[TestWith(['0.5', '10.5000', '5.0000'])]
public function testMod (string $expected, string $left, string $right):void {

self::assertSame($expected, DecimalEngine::mod($left, $right));

}

}