From f2a3d345262df72d4bff8e98f813d640ef3a2ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Bondim?= Date: Fri, 25 Jul 2025 05:04:38 -0300 Subject: [PATCH] feat: clamp --- src/BigDecimal.php | 22 ++++++++++++++++++++++ src/BigInteger.php | 23 +++++++++++++++++++++++ tests/BigDecimalTest.php | 22 ++++++++++++++++++++++ tests/BigIntegerTest.php | 22 ++++++++++++++++++++++ 4 files changed, 89 insertions(+) diff --git a/src/BigDecimal.php b/src/BigDecimal.php index 0932fd64..97f5e957 100644 --- a/src/BigDecimal.php +++ b/src/BigDecimal.php @@ -297,6 +297,28 @@ public function exactlyDividedBy(BigNumber|int|float|string $that) : BigDecimal return $this->dividedBy($that, $scale)->stripTrailingZeros(); } + /** + * Limits (clamps) this number between the given minimum and maximum values. + * + * If the number is lower than $min, returns a copy of $min. + * If the number is greater than $max, returns a copy of $max. + * Otherwise, returns this number unchanged. + * + * @param BigNumber|int|float|string $min The minimum. Must be convertible to a BigDecimal. + * @param BigNumber|int|float|string $max The maximum. Must be convertible to a BigDecimal. + * + * @throws MathException If min/max are not convertible to a BigDecimal. + */ + public function clamp(BigNumber|int|float|string $min, BigNumber|int|float|string $max) : BigDecimal + { + if ($this->isLessThan($min)) { + return BigDecimal::of($min); + } elseif ($this->isGreaterThan($max)) { + return BigDecimal::of($max); + } + return $this; + } + /** * Returns this number exponentiated to the given value. * diff --git a/src/BigInteger.php b/src/BigInteger.php index 6ede65e3..a400a6ff 100644 --- a/src/BigInteger.php +++ b/src/BigInteger.php @@ -450,6 +450,29 @@ public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundi return new BigInteger($result); } + /** + * Limits (clamps) this number between the given minimum and maximum values. + * + * If the number is lower than $min, returns a copy of $min. + * If the number is greater than $max, returns a copy of $max. + * Otherwise, returns this number unchanged. + * + * @param BigNumber|int|float|string $min The minimum. Must be convertible to a BigInteger. + * @param BigNumber|int|float|string $max The maximum. Must be convertible to a BigInteger. + * + * @throws MathException If min/max are not convertible to a BigInteger. + */ + public function clamp(BigNumber|int|float|string $min, BigNumber|int|float|string $max) : BigInteger + { + if ($this->isLessThan($min)) { + return BigInteger::of($min); + } elseif ($this->isGreaterThan($max)) { + return BigInteger::of($max); + } + return $this; + } + + /** * Returns this number exponentiated to the given value. * diff --git a/tests/BigDecimalTest.php b/tests/BigDecimalTest.php index 12cbe862..7c63e067 100644 --- a/tests/BigDecimalTest.php +++ b/tests/BigDecimalTest.php @@ -1748,6 +1748,28 @@ public function testSqrtWithNegativeScale() : void $number->sqrt(-1); } + #[DataProvider('providerClamp')] + public function testClamp(string $number, string $min, string $max, string $expected) + { + self::assertBigDecimalEquals($expected, BigDecimal::of($number)->clamp($min, $max)); + } + + public static function providerClamp() : array + { + return [ + ["1.00", "0.50", "1.50", "1.00"], + ["0.25", "0.50", "1.50", "0.50"], + ["2.00", "0.50", "1.50", "1.50"], + ["0.50", "0.50", "1.50", "0.50"], + ["1.50", "0.50", "1.50", "1.50"], + ["0.00", "0.50", "1.50", "0.50"], + ["1.00", "0.50", "1.50", "1.00"], + ["0.25", "0.00", "0.50", "0.25"], + ["-1.00", "0.50", "1.50", "0.50"], + ["-1.00", "-1.50", "-0.50", "-1.00"], + ]; + } + /** * @param string $number The base number. * @param int $exponent The exponent to apply. diff --git a/tests/BigIntegerTest.php b/tests/BigIntegerTest.php index 5457ea85..5c05bfd8 100644 --- a/tests/BigIntegerTest.php +++ b/tests/BigIntegerTest.php @@ -1456,6 +1456,28 @@ public function testModPowZeroThrowsException() : void BigInteger::of(1)->modPow(1, 0); } + #[DataProvider('providerClamp')] + public function testClamp(string $number, string $min, string $max, string $expected) + { + self::assertBigIntegerEquals($expected, BigInteger::of($number)->clamp($min, $max)); + } + + public static function providerClamp() : array + { + return [ + ["100", "50", "150", "100"], + ["25", "50", "150", "50"], + ["200", "50", "150", "150"], + ["50", "50", "150", "50"], + ["150", "50", "150", "150"], + ["0", "50", "150", "50"], + ["100", "50", "150", "100"], + ["25", "0", "50", "25"], + ["-100", "50", "150", "50"], + ["-100", "-150", "-50", "-100"] + ]; + } + /** * @param string $number The base number. * @param int $exponent The exponent to apply.