From 3550ebaa000d3a4b169a8708de727d383c7e7b2e Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Sat, 14 Feb 2026 10:01:06 +0100 Subject: [PATCH] feat: add types to avoid useless runtime checks --- src/BigDecimal.php | 36 ++++++-------------- src/BigInteger.php | 53 +++++++---------------------- src/BigNumber.php | 5 ++- src/BigRational.php | 3 +- tests/BigDecimalTest.php | 28 --------------- tests/BigIntegerTest.php | 73 ---------------------------------------- 6 files changed, 25 insertions(+), 173 deletions(-) diff --git a/src/BigDecimal.php b/src/BigDecimal.php index a4f083bb..95cfa34d 100644 --- a/src/BigDecimal.php +++ b/src/BigDecimal.php @@ -8,18 +8,16 @@ use Brick\Math\Exception\MathException; use Brick\Math\Exception\NegativeNumberException; use Brick\Math\Exception\RoundingNecessaryException; -use Brick\Math\Internal\Calculator; use Brick\Math\Internal\CalculatorRegistry; -use InvalidArgumentException; use LogicException; use Override; +use function assert; use function func_num_args; use function in_array; use function intdiv; use function max; use function rtrim; -use function sprintf; use function str_pad; use function str_repeat; use function strlen; @@ -241,10 +239,9 @@ public function multipliedBy(BigNumber|int|float|string $that): BigDecimal * Returns the result of the division of this number by the given one, at the given scale. * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. - * @param int|null $scale The desired scale. Omitting this parameter is deprecated; it will be required in 0.15. + * @param non-negative-int|null $scale The desired scale. Omitting this parameter is deprecated; it will be required in 0.15. * @param RoundingMode $roundingMode An optional rounding mode, defaults to Unnecessary. * - * @throws InvalidArgumentException If the scale is negative. * @throws MathException If the divisor is not valid, or is not convertible to a BigDecimal. * @throws DivisionByZeroException If the divisor is zero. * @throws RoundingNecessaryException If RoundingMode::Unnecessary is used and the result cannot be represented @@ -268,8 +265,6 @@ public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, E_USER_DEPRECATED, ); $scale = $this->scale; - } elseif ($scale < 0) { - throw new InvalidArgumentException('Scale must not be negative.'); } if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) { @@ -347,6 +342,8 @@ public function dividedByExact(BigNumber|int|float|string $that): BigDecimal } } + assert($scale >= 0); + return $this->dividedBy($that, $scale)->strippedOfTrailingZeros(); } @@ -355,7 +352,7 @@ public function dividedByExact(BigNumber|int|float|string $that): BigDecimal * * The result has a scale of `$this->scale * $exponent`. * - * @throws InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + * @param int<0, 1000000> $exponent * * @pure */ @@ -369,14 +366,6 @@ public function power(int $exponent): BigDecimal return $this; } - if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { - throw new InvalidArgumentException(sprintf( - 'The exponent %d is not in the range 0 to %d.', - $exponent, - Calculator::MAX_POWER, - )); - } - return new BigDecimal(CalculatorRegistry::get()->pow($this->value, $exponent), $this->scale * $exponent); } @@ -498,13 +487,12 @@ public function quotientAndRemainder(BigNumber|int|float|string $that): array /** * Returns the square root of this number, rounded to the given scale according to the given rounding mode. * - * @param int $scale The target scale. Must be non-negative. - * @param RoundingMode $roundingMode The rounding mode to use, defaults to Down. - * ⚠️ WARNING: the default rounding mode was kept as Down for backward - * compatibility, but will change to Unnecessary in version 0.15. Pass a rounding - * mode explicitly to avoid this upcoming breaking change. + * @param non-negative-int $scale The target scale. Must be non-negative. + * @param RoundingMode $roundingMode The rounding mode to use, defaults to Down. + * ⚠️ WARNING: the default rounding mode was kept as Down for backward + * compatibility, but will change to Unnecessary in version 0.15. Pass a rounding + * mode explicitly to avoid this upcoming breaking change. * - * @throws InvalidArgumentException If the scale is negative. * @throws NegativeNumberException If this number is negative. * @throws RoundingNecessaryException If RoundingMode::Unnecessary is used and the result cannot be represented * exactly at the given scale. @@ -522,10 +510,6 @@ public function sqrt(int $scale, RoundingMode $roundingMode = RoundingMode::Down ); } - if ($scale < 0) { - throw new InvalidArgumentException('Scale must not be negative.'); - } - if ($this->value === '0') { return new BigDecimal('0', $scale); } diff --git a/src/BigInteger.php b/src/BigInteger.php index bd2383c3..e671f54a 100644 --- a/src/BigInteger.php +++ b/src/BigInteger.php @@ -78,11 +78,10 @@ protected function __construct(string $value) * * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method. * - * @param string $number The number to convert, in the given base. - * @param int $base The base of the number, between 2 and 36. + * @param string $number The number to convert, in the given base. + * @param int<2, 36> $base The base of the number, between 2 and 36. * - * @throws NumberFormatException If the number is empty, or contains invalid chars for the given base. - * @throws InvalidArgumentException If the base is out of range. + * @throws NumberFormatException If the number is empty, or contains invalid chars for the given base. * * @pure */ @@ -92,10 +91,6 @@ public static function fromBase(string $number, int $base): BigInteger throw new NumberFormatException('The number must not be empty.'); } - if ($base < 2 || $base > 36) { - throw new InvalidArgumentException(sprintf('Base %d is not in range 2 to 36.', $base)); - } - if ($number[0] === '-') { $sign = '-'; $number = substr($number, 1); @@ -230,19 +225,13 @@ public static function fromBytes(string $value, bool $signed = true): BigInteger * * Using the default random bytes generator, this method is suitable for cryptographic use. * - * @param int $numBits The number of bits. + * @param non-negative-int $numBits The number of bits. * @param (callable(int): string)|null $randomBytesGenerator A function that accepts a number of bytes, and returns * a string of random bytes of the given length. Defaults * to the `random_bytes()` function. - * - * @throws InvalidArgumentException If $numBits is negative. */ public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null): BigInteger { - if ($numBits < 0) { - throw new InvalidArgumentException('The number of bits must not be negative.'); - } - if ($numBits === 0) { return BigInteger::zero(); } @@ -531,7 +520,7 @@ public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundi /** * Returns this number exponentiated to the given value. * - * @throws InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + * @param int<0, 1000000> $exponent * * @pure */ @@ -545,14 +534,6 @@ public function power(int $exponent): BigInteger return $this; } - if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { - throw new InvalidArgumentException(sprintf( - 'The exponent %d is not in the range 0 to %d.', - $exponent, - Calculator::MAX_POWER, - )); - } - return new BigInteger(CalculatorRegistry::get()->pow($this->value, $exponent)); } @@ -972,7 +953,7 @@ public function not(): BigInteger /** * Returns the integer left shifted by a given number of bits. * - * @throws InvalidArgumentException If the number of bits is out of range. + * @param int<-1000000, 1000000> $distance * * @pure */ @@ -992,7 +973,7 @@ public function shiftedLeft(int $distance): BigInteger /** * Returns the integer right shifted by a given number of bits. * - * @throws InvalidArgumentException If the number of bits is out of range. + * @param int<-1000000, 1000000> $distance * * @pure */ @@ -1021,6 +1002,8 @@ public function shiftedRight(int $distance): BigInteger * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation. * Computes (ceil(log2(this < 0 ? -this : this+1))). * + * @return non-negative-int + * * @pure */ public function getBitLength(): int @@ -1064,18 +1047,12 @@ public function getLowestSetBit(): int * * Computes ((this & (1< $n The bit to test, 0-based. * * @pure */ public function isBitSet(int $n): bool { - if ($n < 0) { - throw new InvalidArgumentException('The bit to test cannot be negative.'); - } - return $this->shiftedRight($n)->isOdd(); } @@ -1106,9 +1083,7 @@ public function isOdd(): bool * * @deprecated Use isBitSet(). * - * @param int $n The bit to test, 0-based. - * - * @throws InvalidArgumentException If the bit to test is negative. + * @param int<0, 1000000> $n The bit to test, 0-based. */ public function testBit(int $n): bool { @@ -1185,7 +1160,7 @@ public function toFloat(): float * * The output will always be lowercase for bases greater than 10. * - * @throws InvalidArgumentException If the base is out of range. + * @param int<2, 36> $base * * @pure */ @@ -1195,10 +1170,6 @@ public function toBase(int $base): string return $this->value; } - if ($base < 2 || $base > 36) { - throw new InvalidArgumentException(sprintf('Base %d is out of range [2, 36]', $base)); - } - return CalculatorRegistry::get()->toBase($this->value, $base); } diff --git a/src/BigNumber.php b/src/BigNumber.php index ec9d64cb..5f345497 100644 --- a/src/BigNumber.php +++ b/src/BigNumber.php @@ -441,10 +441,9 @@ abstract public function toBigRational(): BigRational; /** * Converts this number to a BigDecimal with the given scale, using rounding if necessary. * - * @param int $scale The scale of the resulting `BigDecimal`. Must be non-negative. - * @param RoundingMode $roundingMode An optional rounding mode, defaults to Unnecessary. + * @param non-negative-int $scale The scale of the resulting `BigDecimal`. Must be non-negative. + * @param RoundingMode $roundingMode An optional rounding mode, defaults to Unnecessary. * - * @throws InvalidArgumentException If the scale is negative. * @throws RoundingNecessaryException If RoundingMode::Unnecessary is used, and this number cannot be converted to * the given scale without rounding. * diff --git a/src/BigRational.php b/src/BigRational.php index f266a717..6936798e 100644 --- a/src/BigRational.php +++ b/src/BigRational.php @@ -8,7 +8,6 @@ use Brick\Math\Exception\MathException; use Brick\Math\Exception\NumberFormatException; use Brick\Math\Exception\RoundingNecessaryException; -use InvalidArgumentException; use LogicException; use Override; @@ -354,7 +353,7 @@ public function dividedBy(BigNumber|int|float|string $that): BigRational /** * Returns this number exponentiated to the given value. * - * @throws InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + * @param int<0, 1000000> $exponent * * @pure */ diff --git a/tests/BigDecimalTest.php b/tests/BigDecimalTest.php index 159bcfb3..d6138b4e 100644 --- a/tests/BigDecimalTest.php +++ b/tests/BigDecimalTest.php @@ -969,12 +969,6 @@ public static function providerDividedByWithRoundingNecessaryThrowsException(): ]; } - public function testDividedByWithNegativeScaleThrowsException(): void - { - $this->expectException(InvalidArgumentException::class); - BigDecimal::of(1)->dividedBy(2, -1); - } - /** * @param RoundingMode $roundingMode The rounding mode. * @param string $number The number to round. @@ -3040,13 +3034,6 @@ public function testSqrtOfNegativeNumber(): void $number->sqrt(0); } - public function testSqrtWithNegativeScale(): void - { - $number = BigDecimal::of(1); - $this->expectException(InvalidArgumentException::class); - $number->sqrt(-1); - } - public function testSqrtWithoutRoundingModeTriggersDeprecation(): void { $this->expectUserDeprecationMessage( @@ -3148,21 +3135,6 @@ public static function providerPower(): array ]; } - #[DataProvider('providerPowerWithInvalidExponentThrowsException')] - public function testPowerWithInvalidExponentThrowsException(int $power): void - { - $this->expectException(InvalidArgumentException::class); - BigDecimal::of(1)->power($power); - } - - public static function providerPowerWithInvalidExponentThrowsException(): array - { - return [ - [-1], - [1000001], - ]; - } - /** * @param string $number The number to scale. * @param int $toScale The scale to apply. diff --git a/tests/BigIntegerTest.php b/tests/BigIntegerTest.php index 62458486..d075d2ac 100644 --- a/tests/BigIntegerTest.php +++ b/tests/BigIntegerTest.php @@ -356,24 +356,6 @@ public static function providerFromBaseWithInvalidValue(): array ]; } - #[DataProvider('providerFromBaseWithInvalidBase')] - public function testFromBaseWithInvalidBase(int $base): void - { - $this->expectException(InvalidArgumentException::class); - BigInteger::fromBase('0', $base); - } - - public static function providerFromBaseWithInvalidBase(): array - { - return [ - [-2], - [-1], - [0], - [1], - [37], - ]; - } - public function testZero(): void { self::assertBigIntegerEquals('0', BigInteger::zero()); @@ -1657,21 +1639,6 @@ public static function providerPower(): array ]; } - #[DataProvider('providerPowerWithInvalidExponentThrowsException')] - public function testPowerWithInvalidExponentThrowsException(int $power): void - { - $this->expectException(InvalidArgumentException::class); - BigInteger::of(1)->power($power); - } - - public static function providerPowerWithInvalidExponentThrowsException(): array - { - return [ - [-1], - [1000001], - ]; - } - /** * @param string $a The first number. * @param string $b The second number. @@ -4288,22 +4255,6 @@ public static function providerIsBitSet(): Generator } } - public function testIsBitSetWithNegativeBitThrowsException(): void - { - $number = BigInteger::one(); - - $this->expectException(InvalidArgumentException::class); - $number->isBitSet(-1); - } - - public function testTestNegativeBitThrowsException(): void - { - $number = BigInteger::one(); - - $this->expectException(InvalidArgumentException::class); - $number->testBit(-1); - } - /** * @param string $number The number to test. * @param bool $isOdd Whether the number is even. @@ -4754,24 +4705,6 @@ public static function providerToBase(): Generator } } - #[DataProvider('providerToInvalidBaseThrowsException')] - public function testToInvalidBaseThrowsException(int $base): void - { - $this->expectException(InvalidArgumentException::class); - BigInteger::of(0)->toBase($base); - } - - public static function providerToInvalidBaseThrowsException(): array - { - return [ - [-2], - [-1], - [0], - [1], - [37], - ]; - } - #[DataProvider('providerFromArbitraryBase')] public function testFromArbitraryBase(string $base10, string $alphabet, string $baseN): void { @@ -5249,12 +5182,6 @@ public static function providerRandomBits(): array ]; } - public function testRandomBitsWithNegativeBits(): void - { - $this->expectException(InvalidArgumentException::class); - BigInteger::randomBits(-1); - } - public function testRandomBitsWithZeroBits(): void { $random = BigInteger::randomBits(0);