From e54ad079dca2bd540a1a42b0be0a903e0934c890 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Sat, 18 Nov 2023 13:41:41 +0100 Subject: [PATCH 01/16] More specific return type for getSign() & compareTo() --- src/BigNumber.php | 6 +++++- src/Internal/Calculator.php | 4 +++- src/Internal/Calculator/NativeCalculator.php | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/BigNumber.php b/src/BigNumber.php index 94cedab..1161676 100644 --- a/src/BigNumber.php +++ b/src/BigNumber.php @@ -415,6 +415,8 @@ public function isPositiveOrZero() : bool /** * Returns the sign of this number. * + * @psalm-return -1|0|1 + * * @return int -1 if the number is negative, 0 if zero, 1 if positive. */ abstract public function getSign() : int; @@ -422,7 +424,9 @@ abstract public function getSign() : int; /** * Compares this number to the given one. * - * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`. + * @psalm-return -1|0|1 + * + * @return int -1 if `$this` is lower than, 0 if equal to, 1 if greater than `$that`. * * @throws MathException If the number is not valid. */ diff --git a/src/Internal/Calculator.php b/src/Internal/Calculator.php index b2b55cd..fb8e06f 100644 --- a/src/Internal/Calculator.php +++ b/src/Internal/Calculator.php @@ -128,7 +128,9 @@ final public function neg(string $n) : string /** * Compares two numbers. * - * @return int [-1, 0, 1] If the first number is less than, equal to, or greater than the second number. + * @psalm-return -1|0|1 + * + * @return int -1 if the first number is less than, 0 if equal to, 1 if greater than the second number. */ final public function cmp(string $a, string $b) : int { diff --git a/src/Internal/Calculator/NativeCalculator.php b/src/Internal/Calculator/NativeCalculator.php index 780df14..70a5159 100644 --- a/src/Internal/Calculator/NativeCalculator.php +++ b/src/Internal/Calculator/NativeCalculator.php @@ -527,7 +527,7 @@ private function doDiv(string $a, string $b) : array /** * Compares two non-signed large numbers. * - * @return int [-1, 0, 1] + * @psalm-return -1|0|1 */ private function doCmp(string $a, string $b) : int { @@ -540,7 +540,7 @@ private function doCmp(string $a, string $b) : int return $cmp; } - return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1] + return \strcmp($a, $b) <=> 0; // enforce -1|0|1 } /** From 8c4b308bbb816d34edfc3b9d198422386da28412 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Sat, 18 Nov 2023 13:44:37 +0100 Subject: [PATCH 02/16] Update Psalm to 5.15.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9d5bd2a..d465543 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "require-dev": { "phpunit/phpunit": "^9.0", "php-coveralls/php-coveralls": "^2.2", - "vimeo/psalm": "5.14.1" + "vimeo/psalm": "5.15.0" }, "autoload": { "psr-4": { From 12b318b7bb4c971a045c9a2f5427b5a84b0ecfea Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Sat, 18 Nov 2023 13:45:49 +0100 Subject: [PATCH 03/16] Remove ImpureByReferenceAssignment error suppression --- psalm.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/psalm.xml b/psalm.xml index 3cb8844..a142b24 100644 --- a/psalm.xml +++ b/psalm.xml @@ -21,11 +21,5 @@ - - - - - - From 1e580a3fc35a1a2363e08e20740ba5657d2b033d Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Tue, 1 Aug 2023 11:36:46 +0200 Subject: [PATCH 04/16] Require PHP 8.1 --- .github/workflows/ci.yml | 9 ++++----- CHANGELOG.md | 6 ++++++ README.md | 34 +++++++++++++++++----------------- composer.json | 2 +- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 559aeca..c9fcbb0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: "8.1" + php-version: "8.2" - name: Install composer dependencies uses: "ramsey/composer-install@v1" @@ -31,7 +31,6 @@ jobs: strategy: matrix: php-version: - - "8.0" - "8.1" - "8.2" - "8.3" @@ -57,7 +56,7 @@ jobs: run: vendor/bin/phpunit env: CALCULATOR: ${{ matrix.calculator }} - if: ${{ matrix.php-version != '8.0' }} + if: ${{ matrix.php-version != '8.2' }} - name: Run PHPUnit with coverage run: | @@ -65,7 +64,7 @@ jobs: vendor/bin/phpunit --coverage-clover build/logs/clover.xml env: CALCULATOR: ${{ matrix.calculator }} - if: ${{ matrix.php-version == '8.0' }} + if: ${{ matrix.php-version == '8.2' }} - name: Run PHPUnit with bcscale() run: vendor/bin/phpunit @@ -78,4 +77,4 @@ jobs: run: vendor/bin/php-coveralls --coverage_clover=build/logs/clover.xml -v env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: ${{ matrix.php-version == '8.0' }} + if: ${{ matrix.php-version == '8.2' }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 17cea8d..f52569f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## UNRELEASED (0.12.0) + +💥 **Breaking changes** + +- Minimum PHP version is now 8.1 + ## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16 💥 **Breaking changes** diff --git a/README.md b/README.md index 15781fd..0c214ce 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ composer require brick/math ### Requirements -This library requires PHP 8.0 or later. +This library requires PHP 8.1 or later. -For PHP 7.4 compatibility, you can use version `0.10`. For PHP 7.1, 7.2 & 7.3, you can use version `0.9`. Note that [these PHP versions are EOL](http://php.net/supported-versions.php) and not supported anymore. If you're still using one of these PHP versions, you should consider upgrading as soon as possible. +For PHP 8.0 compatibility, you can use version `0.12`. For PHP 7.4, you can use version `0.10`. For PHP 7.1, 7.2 & 7.3, you can use version `0.9`. Note that [these PHP versions are EOL](http://php.net/supported-versions.php) and not supported anymore. If you're still using one of these PHP versions, you should consider upgrading as soon as possible. Although the library can work seamlessly on any PHP installation, it is highly recommended that you install the [GMP](http://php.net/manual/en/book.gmp.php) or [BCMath](http://php.net/manual/en/book.bc.php) extension @@ -38,7 +38,7 @@ existing code, etc.), `y` is incremented. **When a breaking change is introduced, a new `0.x` version cycle is always started.** -It is therefore safe to lock your project to a given release cycle, such as `^0.11`. +It is therefore safe to lock your project to a given release cycle, such as `^0.12`. If you need to upgrade to a newer release cycle, check the [release history](https://github.com/brick/math/releases) for a list of changes introduced by each further `0.x.0` version. @@ -47,20 +47,20 @@ for a list of changes introduced by each further `0.x.0` version. This library provides the following public classes in the `Brick\Math` namespace: -- [BigNumber](https://github.com/brick/math/blob/0.11.0/src/BigNumber.php): base class for `BigInteger`, `BigDecimal` and `BigRational` -- [BigInteger](https://github.com/brick/math/blob/0.11.0/src/BigInteger.php): represents an arbitrary-precision integer number. -- [BigDecimal](https://github.com/brick/math/blob/0.11.0/src/BigDecimal.php): represents an arbitrary-precision decimal number. -- [BigRational](https://github.com/brick/math/blob/0.11.0/src/BigRational.php): represents an arbitrary-precision rational number (fraction). -- [RoundingMode](https://github.com/brick/math/blob/0.11.0/src/RoundingMode.php): holds constants for the rounding modes. +- [BigNumber](https://github.com/brick/math/blob/0.12.0/src/BigNumber.php): base class for `BigInteger`, `BigDecimal` and `BigRational` +- [BigInteger](https://github.com/brick/math/blob/0.12.0/src/BigInteger.php): represents an arbitrary-precision integer number. +- [BigDecimal](https://github.com/brick/math/blob/0.12.0/src/BigDecimal.php): represents an arbitrary-precision decimal number. +- [BigRational](https://github.com/brick/math/blob/0.12.0/src/BigRational.php): represents an arbitrary-precision rational number (fraction). +- [RoundingMode](https://github.com/brick/math/blob/0.12.0/src/RoundingMode.php): holds constants for the rounding modes. And the following exceptions in the `Brick\Math\Exception` namespace: -- [MathException](https://github.com/brick/math/blob/0.11.0/src/Exception/MathException.php): base class for all exceptions -- [DivisionByZeroException](https://github.com/brick/math/blob/0.11.0/src/Exception/DivisionByZeroException.php): thrown when a division by zero occurs -- [IntegerOverflowException](https://github.com/brick/math/blob/0.11.0/src/Exception/IntegerOverflowException.php): thrown when attempting to convert a too large `BigInteger` to `int` -- [NumberFormatException](https://github.com/brick/math/blob/0.11.0/src/Exception/NumberFormatException.php): thrown when parsing a number string in an invalid format -- [RoundingNecessaryException](https://github.com/brick/math/blob/0.11.0/src/Exception/RoundingNecessaryException.php): thrown when the result of the operation cannot be represented without explicit rounding -- [NegativeNumberException](https://github.com/brick/math/blob/0.11.0/src/Exception/NegativeNumberException.php): thrown when attempting to calculate the square root of a negative number +- [MathException](https://github.com/brick/math/blob/0.12.0/src/Exception/MathException.php): base class for all exceptions +- [DivisionByZeroException](https://github.com/brick/math/blob/0.12.0/src/Exception/DivisionByZeroException.php): thrown when a division by zero occurs +- [IntegerOverflowException](https://github.com/brick/math/blob/0.12.0/src/Exception/IntegerOverflowException.php): thrown when attempting to convert a too large `BigInteger` to `int` +- [NumberFormatException](https://github.com/brick/math/blob/0.12.0/src/Exception/NumberFormatException.php): thrown when parsing a number string in an invalid format +- [RoundingNecessaryException](https://github.com/brick/math/blob/0.12.0/src/Exception/RoundingNecessaryException.php): thrown when the result of the operation cannot be represented without explicit rounding +- [NegativeNumberException](https://github.com/brick/math/blob/0.12.0/src/Exception/NegativeNumberException.php): thrown when attempting to calculate the square root of a negative number ### Overview @@ -88,7 +88,7 @@ BigRational::of('2/3'); BigRational::of('1.1'); // 11/10 ``` -Note that all `of()` methods accept all of the representations above, *as long as it can be safely converted to +Note that all `of()` methods accept all the representations above, *as long as it can be safely converted to the current type*: ```php @@ -174,7 +174,7 @@ echo BigInteger::of(999)->dividedBy(3); // 333 echo BigInteger::of(1000)->dividedBy(3); // RoundingNecessaryException ``` -You can pass an optional [rounding mode](https://github.com/brick/math/blob/0.11.0/src/RoundingMode.php) to round the result, if necessary: +You can pass an optional [rounding mode](https://github.com/brick/math/blob/0.12.0/src/RoundingMode.php) to round the result, if necessary: ```php echo BigInteger::of(1000)->dividedBy(3, RoundingMode::DOWN); // 333 @@ -197,7 +197,7 @@ You can even get both at the same time: ##### BigDecimal Dividing a `BigDecimal` always requires a scale to be specified. If the exact result of the division does not fit in -the given scale, a [rounding mode](https://github.com/brick/math/blob/0.11.0/src/RoundingMode.php) must be provided. +the given scale, a [rounding mode](https://github.com/brick/math/blob/0.12.0/src/RoundingMode.php) must be provided. ```php echo BigDecimal::of(1)->dividedBy('8', 3); // 0.125 diff --git a/composer.json b/composer.json index d465543..07441fc 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ ], "license": "MIT", "require": { - "php": "^8.0" + "php": "^8.1" }, "require-dev": { "phpunit/phpunit": "^9.0", From 1d4b51d66a1f8e0d09ce89880c908fbbf470a5db Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Tue, 1 Aug 2023 11:46:51 +0200 Subject: [PATCH 05/16] Upgrade to PHPUnit 10 --- .gitignore | 2 +- composer.json | 2 +- phpunit.xml | 8 +- tests/BigDecimalTest.php | 76 ++++++------ tests/BigIntegerTest.php | 108 +++++++++--------- tests/BigNumberTest.php | 2 +- tests/BigRationalTest.php | 48 ++++---- .../Calculator/NativeCalculatorTest.php | 6 +- 8 files changed, 126 insertions(+), 126 deletions(-) diff --git a/.gitignore b/.gitignore index 4901aab..8ae88e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /vendor /composer.lock -/.phpunit.result.cache +/.phpunit.cache diff --git a/composer.json b/composer.json index 07441fc..3835536 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "php": "^8.1" }, "require-dev": { - "phpunit/phpunit": "^9.0", + "phpunit/phpunit": "^10.1", "php-coveralls/php-coveralls": "^2.2", "vimeo/psalm": "5.15.0" }, diff --git a/phpunit.xml b/phpunit.xml index a292a18..bfaec18 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,13 +1,13 @@ - + tests - + - src + src - + diff --git a/tests/BigDecimalTest.php b/tests/BigDecimalTest.php index f8d3443..700d4c4 100644 --- a/tests/BigDecimalTest.php +++ b/tests/BigDecimalTest.php @@ -29,7 +29,7 @@ public function testOf($value, string $unscaledValue, int $scale) : void self::assertBigDecimalInternalValues($unscaledValue, $scale, BigDecimal::of($value)); } - public function providerOf() : array + public static function providerOf() : array { return [ [0, '0', 0], @@ -206,7 +206,7 @@ public function testOfFloatInDifferentLocales(string $locale) : void setlocale(LC_NUMERIC, $originalLocale); } - public function providerOfFloatInDifferentLocales() : array + public static function providerOfFloatInDifferentLocales() : array { return [ ['C'], @@ -231,7 +231,7 @@ public function testOfInvalidValueThrowsException($value) : void BigDecimal::of($value); } - public function providerOfInvalidValueThrowsException() : array + public static function providerOfInvalidValueThrowsException() : array { return [ [''], @@ -282,7 +282,7 @@ public function testOfUnscaledValue($unscaledValue, int $scale, string $expected self::assertBigDecimalInternalValues($expectedUnscaledValue, $scale, $number); } - public function providerOfUnscaledValue() : array + public static function providerOfUnscaledValue() : array { return [ [123456789, 0, '123456789'], @@ -347,7 +347,7 @@ public function testMin(array $values, string $min) : void self::assertBigDecimalEquals($min, BigDecimal::min(... $values)); } - public function providerMin() : array + public static function providerMin() : array { return [ [[0, 1, -1], '-1'], @@ -388,7 +388,7 @@ public function testMax(array $values, string $max) : void self::assertBigDecimalEquals($max, BigDecimal::max(... $values)); } - public function providerMax() : array + public static function providerMax() : array { return [ [[0, 0.9, -1.00], '0.9'], @@ -433,7 +433,7 @@ public function testSum(array $values, string $sum) : void self::assertBigDecimalEquals($sum, BigDecimal::sum(... $values)); } - public function providerSum() : array + public static function providerSum() : array { return [ [[0, 0.9, -1.00], '-0.1'], @@ -480,7 +480,7 @@ public function testPlus(string $a, string $b, string $unscaledValue, int $scale self::assertBigDecimalInternalValues($unscaledValue, $scale, BigDecimal::of($a)->plus($b)); } - public function providerPlus() : array + public static function providerPlus() : array { return [ ['123', '999', '1122', 0], @@ -556,7 +556,7 @@ public function testMinus(string $a, string $b, string $unscaledValue, int $scal self::assertBigDecimalInternalValues($unscaledValue, $scale, BigDecimal::of($a)->minus($b)); } - public function providerMinus() : array + public static function providerMinus() : array { return [ ['123', '999', '-876', 0], @@ -625,7 +625,7 @@ public function testMultipliedBy(string $a, string $b, string $unscaledValue, in self::assertBigDecimalInternalValues($unscaledValue, $scale, BigDecimal::of($a)->multipliedBy($b)); } - public function providerMultipliedBy() : array + public static function providerMultipliedBy() : array { return [ ['123', '999', '122877', 0], @@ -739,7 +739,7 @@ public function testDividedBy(string $a, string $b, ?int $scale, int $roundingMo self::assertBigDecimalInternalValues($unscaledValue, $expectedScale, $decimal); } - public function providerDividedBy() : array + public static function providerDividedBy() : array { return [ [ '7', '0.2', 0, RoundingMode::UNNECESSARY, '35', 0], @@ -774,7 +774,7 @@ public function testDividedByByZeroThrowsException($zero) : void BigDecimal::of(1)->dividedBy($zero, 0); } - public function providerDividedByByZeroThrowsException() : array + public static function providerDividedByByZeroThrowsException() : array { return [ [0], @@ -807,7 +807,7 @@ public function testExactlyDividedBy($number, $divisor, string $expected) : void } } - public function providerExactlyDividedBy() : array + public static function providerExactlyDividedBy() : array { return [ [1, 1, '1'], @@ -860,7 +860,7 @@ public function testDividedByWithRoundingNecessaryThrowsException(string $a, str BigDecimal::of($a)->dividedBy($b, $scale); } - public function providerDividedByWithRoundingNecessaryThrowsException() : array + public static function providerDividedByWithRoundingNecessaryThrowsException() : array { return [ ['1.234', '123.456', 3], @@ -921,7 +921,7 @@ private function doTestRoundingMode(int $roundingMode, BigDecimal $number, strin } } - public function providerRoundingMode() : array + public static function providerRoundingMode() : array { return [ [RoundingMode::UP, '3.501', '351', '36', '4'], @@ -1407,7 +1407,7 @@ public function testQuotientAndRemainder(string $dividend, string $divisor, stri self::assertBigDecimalEquals($remainder, $r); } - public function providerQuotientAndRemainder() : array + public static function providerQuotientAndRemainder() : array { return [ ['1', '123', '0', '1'], @@ -1504,7 +1504,7 @@ public function testSqrt(string $number, int $scale, string $sqrt) : void self::assertBigDecimalEquals($sqrt, $number->sqrt($scale)); } - public function providerSqrt() : array + public static function providerSqrt() : array { return [ ['0', 0, '0'], @@ -1728,7 +1728,7 @@ public function testPower(string $number, int $exponent, string $unscaledValue, self::assertBigDecimalInternalValues($unscaledValue, $scale, BigDecimal::of($number)->power($exponent)); } - public function providerPower() : array + public static function providerPower() : array { return [ ['-3', 0, '1', 0], @@ -1788,7 +1788,7 @@ public function testPowerWithInvalidExponentThrowsException(int $power) : void BigDecimal::of(1)->power($power); } - public function providerPowerWithInvalidExponentThrowsException() : array + public static function providerPowerWithInvalidExponentThrowsException() : array { return [ [-1], @@ -1797,7 +1797,7 @@ public function providerPowerWithInvalidExponentThrowsException() : array } /** - * @dataProvider toScaleProvider + * @dataProvider providerToScale * * @param string $number The number to scale. * @param int $toScale The scale to apply. @@ -1811,7 +1811,7 @@ public function testToScale(string $number, int $toScale, int $roundingMode, str self::assertBigDecimalInternalValues($unscaledValue, $scale, $decimal); } - public function toScaleProvider() : array + public static function providerToScale() : array { return [ ['123.45', 0, RoundingMode::DOWN, '123', 0], @@ -1833,7 +1833,7 @@ public function testWithPointMovedLeft(string $number, int $places, string $expe self::assertBigDecimalEquals($expected, BigDecimal::of($number)->withPointMovedLeft($places)); } - public function providerWithPointMovedLeft() : array + public static function providerWithPointMovedLeft() : array { return [ ['0', -2, '0'], @@ -1916,7 +1916,7 @@ public function testWithPointMovedRight(string $number, int $places, string $exp self::assertBigDecimalEquals($expected, BigDecimal::of($number)->withPointMovedRight($places)); } - public function providerWithPointMovedRight() : array + public static function providerWithPointMovedRight() : array { return [ ['0', -2, '0.00'], @@ -1998,7 +1998,7 @@ public function testStripTrailingZeros(string $number, string $expected) : void self::assertBigDecimalEquals($expected, BigDecimal::of($number)->stripTrailingZeros()); } - public function providerStripTrailingZeros() : array + public static function providerStripTrailingZeros() : array { return [ ['0', '0'], @@ -2044,7 +2044,7 @@ public function testAbs(string $number, string $unscaledValue, int $scale) : voi self::assertBigDecimalInternalValues($unscaledValue, $scale, BigDecimal::of($number)->abs()); } - public function providerAbs() : array + public static function providerAbs() : array { return [ ['123', '123', 0], @@ -2066,7 +2066,7 @@ public function testNegated(string $number, string $unscaledValue, int $scale) : self::assertBigDecimalInternalValues($unscaledValue, $scale, BigDecimal::of($number)->negated()); } - public function providerNegated() : array + public static function providerNegated() : array { return [ ['123', '-123', 0], @@ -2148,7 +2148,7 @@ public function testIsGreaterThanOrEqualTo(string $a, $b, int $c) : void self::assertSame($c >= 0, BigDecimal::of($a)->isGreaterThanOrEqualTo($b)); } - public function providerCompareTo() : array + public static function providerCompareTo() : array { return [ ['123', '123', 0], @@ -2263,7 +2263,7 @@ public function testIsPositiveOrZero($number, int $sign) : void self::assertSame($sign >= 0, BigDecimal::of($number)->isPositiveOrZero()); } - public function providerSign() : array + public static function providerSign() : array { return [ [ 0, 0], @@ -2307,7 +2307,7 @@ public function testGetIntegralPart(string $number, string $expected) : void self::assertSame($expected, BigDecimal::of($number)->getIntegralPart()); } - public function providerGetIntegralPart() : array + public static function providerGetIntegralPart() : array { return [ ['1.23', '1'], @@ -2331,7 +2331,7 @@ public function testGetFractionalPart(string $number, string $expected) : void self::assertSame($expected, BigDecimal::of($number)->getFractionalPart()); } - public function providerGetFractionalPart() : array + public static function providerGetFractionalPart() : array { return [ ['1.23', '23'], @@ -2354,7 +2354,7 @@ public function testHasNonZeroFractionalPart(string $number, bool $hasNonZeroFra self::assertSame($hasNonZeroFractionalPart, BigDecimal::of($number)->hasNonZeroFractionalPart()); } - public function providerHasNonZeroFractionalPart() : array + public static function providerHasNonZeroFractionalPart() : array { return [ ['1', false], @@ -2377,7 +2377,7 @@ public function testToBigInteger(string $decimal, string $expected) : void self::assertBigIntegerEquals($expected, BigDecimal::of($decimal)->toBigInteger()); } - public function providerToBigInteger() : array + public static function providerToBigInteger() : array { return [ ['0', '0'], @@ -2399,7 +2399,7 @@ public function testToBigIntegerThrowsExceptionWhenRoundingNecessary(string $dec BigDecimal::of($decimal)->toBigInteger(); } - public function providerToBigIntegerThrowsExceptionWhenRoundingNecessary() : array + public static function providerToBigIntegerThrowsExceptionWhenRoundingNecessary() : array { return [ ['0.1'], @@ -2425,7 +2425,7 @@ public function testToBigRational(string $decimal, string $rational) : void self::assertBigRationalEquals($rational, BigDecimal::of($decimal)->toBigRational()); } - public function providerToBigRational() : array + public static function providerToBigRational() : array { return [ ['0', '0'], @@ -2469,7 +2469,7 @@ public function testToInt(int $number) : void self::assertSame($number, BigDecimal::of($number . '.0')->toInt()); } - public function providerToInt() : array + public static function providerToInt() : array { return [ [PHP_INT_MIN], @@ -2493,7 +2493,7 @@ public function testToIntThrowsException(string $number) : void BigDecimal::of($number)->toInt(); } - public function providerToIntThrowsException() : array + public static function providerToIntThrowsException() : array { return [ ['-999999999999999999999999999999'], @@ -2514,7 +2514,7 @@ public function testToFloat(string $value, float $float) : void self::assertSame($float, BigDecimal::of($value)->toFloat()); } - public function providerToFloat() : array + public static function providerToFloat() : array { return [ ['0', 0.0], @@ -2539,7 +2539,7 @@ public function testToString(string $unscaledValue, int $scale, string $expected self::assertSame($expected, (string) BigDecimal::ofUnscaledValue($unscaledValue, $scale)); } - public function providerToString() : array + public static function providerToString() : array { return [ ['0', 0, '0'], diff --git a/tests/BigIntegerTest.php b/tests/BigIntegerTest.php index 2c4aa89..54e9301 100644 --- a/tests/BigIntegerTest.php +++ b/tests/BigIntegerTest.php @@ -32,7 +32,7 @@ public function testOf($value, string $expected) : void self::assertBigIntegerEquals($expected, BigInteger::of($value)); } - public function providerOf() : array + public static function providerOf() : array { return [ [0, '0'], @@ -122,7 +122,7 @@ public function testOfInvalidFormatThrowsException($value) : void BigInteger::of($value); } - public function providerOfInvalidFormatThrowsException() : array + public static function providerOfInvalidFormatThrowsException() : array { return [ [''], @@ -151,7 +151,7 @@ public function testOfNonConvertibleValueThrowsException($value) : void BigInteger::of($value); } - public function providerOfNonConvertibleValueThrowsException() : array + public static function providerOfNonConvertibleValueThrowsException() : array { return [ [1.1], @@ -175,7 +175,7 @@ public function testFromBase(string $number, int $base, string $expected) : void /** * @return array */ - public function providerFromBase() : array + public static function providerFromBase() : array { return [ ['0', 10, '0'], @@ -289,7 +289,7 @@ public function testFromBaseWithInvalidValue(string $value, int $base) : void BigInteger::fromBase($value, $base); } - public function providerFromBaseWithInvalidValue() : array + public static function providerFromBaseWithInvalidValue() : array { return [ ['', 10], @@ -345,7 +345,7 @@ public function testFromBaseWithInvalidBase(int $base) : void BigInteger::fromBase('0', $base); } - public function providerFromBaseWithInvalidBase() : array + public static function providerFromBaseWithInvalidBase() : array { return [ [-2], @@ -387,7 +387,7 @@ public function testGcdMultiple(array $values, string $expectedGCD): void self::assertSame($expectedGCD, (string) $actualGCD); } - public function providerGcdMultiple(): Generator + public static function providerGcdMultiple(): Generator { // 1 value foreach (['-2', '-1', '0', '1', '2'] as $value) { @@ -395,7 +395,7 @@ public function providerGcdMultiple(): Generator } // 2 values - foreach ($this->providerGcd() as [$a, $b, $gcd]) { + foreach (self::providerGcd() as [$a, $b, $gcd]) { yield [[$a, $b], $gcd]; } @@ -425,7 +425,7 @@ public function testMin(array $values, string $min) : void self::assertBigIntegerEquals($min, BigInteger::min(... $values)); } - public function providerMin() : array + public static function providerMin() : array { return [ [[0, 1, -1], '-1'], @@ -461,7 +461,7 @@ public function testMax(array $values, string $max) : void self::assertBigIntegerEquals($max, BigInteger::max(... $values)); } - public function providerMax() : array + public static function providerMax() : array { return [ [[0, 1, -1], '1'], @@ -498,7 +498,7 @@ public function testSum(array $values, string $sum) : void self::assertBigIntegerEquals($sum, BigInteger::sum(... $values)); } - public function providerSum() : array + public static function providerSum() : array { return [ [[-1], '-1'], @@ -537,7 +537,7 @@ public function testPlus(string $a, string $b, string $r) : void self::assertBigIntegerEquals($r, BigInteger::of($a)->plus($b)); } - public function providerPlus() : array + public static function providerPlus() : array { return [ ['5165450198704521651351654564564089798441', '0', '5165450198704521651351654564564089798441'], @@ -566,7 +566,7 @@ public function testMinus(string $a, string $b, string $r) : void self::assertBigIntegerEquals($r, BigInteger::of($a)->minus($b)); } - public function providerMinus() : array + public static function providerMinus() : array { return [ ['5165450198704521651351654564564089798441', '0', '5165450198704521651351654564564089798441'], @@ -593,7 +593,7 @@ public function testMultipliedBy(string $a, $b, string $r) : void self::assertBigIntegerEquals($r, BigInteger::of($a)->multipliedBy($b)); } - public function providerMultipliedBy() : array + public static function providerMultipliedBy() : array { return [ ['123456789098765432101234567890987654321', '1', '123456789098765432101234567890987654321'], @@ -637,7 +637,7 @@ public function testDividedBy(string $number, $divisor, string $expected) : void } } - public function providerDividedBy() : array + public static function providerDividedBy() : array { return [ ['123456789098765432101234567890987654321', 1, '123456789098765432101234567890987654321'], @@ -708,7 +708,7 @@ private function doTestDividedByWithRoundingMode(int $roundingMode, BigInteger $ } } - public function providerDividedByWithRoundingMode() : array + public static function providerDividedByWithRoundingMode() : array { return [ [RoundingMode::UP, '3501', '351', '36', '4'], @@ -1226,7 +1226,7 @@ public function testQuotientAndRemainder(string $dividend, string $divisor, stri self::assertBigIntegerEquals($remainder, $r); } - public function providerQuotientAndRemainder() : array + public static function providerQuotientAndRemainder() : array { return [ ['1', '123', '0', '1'], @@ -1302,7 +1302,7 @@ public function testMod(string $dividend, string $divisor, string $expected) : v self::assertBigIntegerEquals($expected, BigInteger::of($dividend)->mod($divisor)); } - public function providerMod() : array + public static function providerMod() : array { return [ ['0', '1', '0'], @@ -1399,7 +1399,7 @@ public function testModPow(string $base, string $exp, string $mod, string $expec self::assertBigIntegerEquals($expected, BigInteger::of($base)->modPow($exp, $mod)); } - public function providerModPow() : array + public static function providerModPow() : array { return [ ['0', '0', '1', '0'], @@ -1476,7 +1476,7 @@ public function testModPowNegativeThrowsException(int $base, int $exp, int $mod) BigInteger::of($base)->modPow($exp, $mod); } - public function providerModPowNegativeThrowsException() : array + public static function providerModPowNegativeThrowsException() : array { return [ [ 1, 1, -1], @@ -1503,7 +1503,7 @@ public function testPower(string $number, int $exponent, string $expected) : voi self::assertBigIntegerEquals($expected, BigInteger::of($number)->power($exponent)); } - public function providerPower() : array + public static function providerPower() : array { return [ ['-3', 0, '1'], @@ -1561,7 +1561,7 @@ public function testPowerWithInvalidExponentThrowsException(int $power) : void BigInteger::of(1)->power($power); } - public function providerPowerWithInvalidExponentThrowsException() : array + public static function providerPowerWithInvalidExponentThrowsException() : array { return [ [-1], @@ -1584,7 +1584,7 @@ public function testGcd(string $a, string $b, string $gcd) : void self::assertBigIntegerEquals($gcd, $a->gcd($b)); } - public function providerGcd() : \Generator + public static function providerGcd() : \Generator { $tests = [ ['0', '0', '0'], @@ -1679,7 +1679,7 @@ public function testSqrt(string $number, string $sqrt) : void self::assertBigIntegerEquals($sqrt, $number->sqrt()); } - public function providerSqrt() : array + public static function providerSqrt() : array { return [ ['0', '0'], @@ -2039,7 +2039,7 @@ public function testAbs(string $number, string $expected) : void self::assertBigIntegerEquals($expected, BigInteger::of($number)->abs()); } - public function providerAbs() : array + public static function providerAbs() : array { return [ ['0', '0'], @@ -2059,7 +2059,7 @@ public function testNegated(string $number, string $expected) : void self::assertBigIntegerEquals($expected, BigInteger::of($number)->negated()); } - public function providerNegated() : array + public static function providerNegated() : array { return [ ['0', '0'], @@ -2080,7 +2080,7 @@ public function testOr(string $a, string $b, string $c) : void self::assertBigIntegerEquals($c, BigInteger::of($a)->or($b)); } - public function providerOr() : array + public static function providerOr() : array { return [ ['-1', '-2', '-1'], @@ -2152,7 +2152,7 @@ public function testAnd(string $a, string $b, string $c) : void self::assertBigIntegerEquals($c, BigInteger::of($a)->and($b)); } - public function providerAnd() : array + public static function providerAnd() : array { return [ ['-1', '-2', '-2'], @@ -2229,7 +2229,7 @@ public function testXor(string $a, string $b, string $c) : void self::assertBigIntegerEquals($c, BigInteger::of($a)->xor($b)); } - public function providerXor() : array + public static function providerXor() : array { return [ ['-1', '-2', '1'], @@ -2299,7 +2299,7 @@ public function testNot(string $number, string $expected) : void self::assertBigIntegerEquals($expected, BigInteger::of($number)->not()); } - public function providerNot() : array + public static function providerNot() : array { return [ ['-32769', '32768'], @@ -2348,7 +2348,7 @@ public function testShiftedRight(string $a, int $b, string $c) : void self::assertBigIntegerEquals($c, BigInteger::of($a)->shiftedRight(- $b)); } - public function providerShiftedLeft() : array + public static function providerShiftedLeft() : array { return [ ['-1', 1, '-2'], @@ -2504,7 +2504,7 @@ public function testGetBitLength(string $number, int $bitLength) : void self::assertSame($bitLength, BigInteger::of($number)->getBitLength()); } - public function providerGetBitLength() : array + public static function providerGetBitLength() : array { return [ ['-10141204801825835211973625643009', 104], @@ -2581,7 +2581,7 @@ public function testGetLowestSetBit(string $number, int $lowestSetBit) : void self::assertSame($lowestSetBit, BigInteger::of($number)->getLowestSetBit()); } - public function providerGetLowestSetBit() : array + public static function providerGetLowestSetBit() : array { return [ ['-10', 1], @@ -2638,7 +2638,7 @@ public function testIsOdd(string $number, bool $isOdd) : void self::assertSame($isOdd, BigInteger::of($number)->isOdd()); } - public function providerIsOdd() : \Generator + public static function providerIsOdd() : \Generator { $tests = [ ['123456789012345678900', false], @@ -2671,7 +2671,7 @@ public function testTestBit(BigInteger $number, int $n, bool $expected) : void self::assertSame($expected, $number->testBit($n)); } - public function providerTestBit() : \Generator + public static function providerTestBit() : \Generator { $base2BitsSetTests = [ ['0', []], @@ -2743,7 +2743,7 @@ public function testModInverse(string $x, string $m, string $expectedResult) : v self::assertSame($expectedResult, (string) $x->modInverse($m)); } - public function providerModInverse() : array + public static function providerModInverse() : array { return [ ['1', '1', '0'], @@ -2775,7 +2775,7 @@ public function testModInverseThrows(string $x, string $m, string $expectedExcep $x->modInverse($m); } - public function providerModInverseThrows() : array + public static function providerModInverseThrows() : array { return [ ['0', '0', DivisionByZeroException::class], @@ -2861,7 +2861,7 @@ public function testIsGreaterThanOrEqualTo(string $a, string $b, int $c) : void self::assertSame($c >= 0, BigInteger::of($a)->isGreaterThanOrEqualTo($b)); } - public function providerCompareTo() : array + public static function providerCompareTo() : array { return [ ['123', '123', 0], @@ -2970,7 +2970,7 @@ public function testIsPositiveOrZero($number, int $sign) : void self::assertSame($sign >= 0, BigInteger::of($number)->isPositiveOrZero()); } - public function providerSign() : array + public static function providerSign() : array { return [ [ 0, 0], @@ -2998,7 +2998,7 @@ public function testToScale(string $number, int $scale, string $expected) : void self::assertBigDecimalEquals($expected, BigInteger::of($number)->toScale($scale)); } - public function providerToScale() : array + public static function providerToScale() : array { return [ ['12345678901234567890123456789', 0, '12345678901234567890123456789'], @@ -3015,7 +3015,7 @@ public function testToInt(int $number) : void self::assertSame($number, BigInteger::of((string) $number)->toInt()); } - public function providerToInt() : array + public static function providerToInt() : array { return [ [PHP_INT_MIN], @@ -3051,7 +3051,7 @@ public function testToFloat(string $value, float $float) : void self::assertSame($float, BigInteger::of($value)->toFloat()); } - public function providerToFloat() : array + public static function providerToFloat() : array { return [ ['0', 0.0], @@ -3076,7 +3076,7 @@ public function testToBase(string $number, int $base, string $expected) : void self::assertSame($expected, BigInteger::of($number)->toBase($base)); } - public function providerToBase() : \Generator + public static function providerToBase() : \Generator { $tests = [ ['640998479760579495168036691627608949', 36, '110011001100110011001111'], @@ -3176,7 +3176,7 @@ public function testToInvalidBaseThrowsException(int $base) : void BigInteger::of(0)->toBase($base); } - public function providerToInvalidBaseThrowsException() : array + public static function providerToInvalidBaseThrowsException() : array { return [ [-2], @@ -3197,9 +3197,9 @@ public function testFromArbitraryBase(string $base10, string $alphabet, string $ self::assertBigIntegerEquals($base10, $number); } - public function providerFromArbitraryBase() : \Generator + public static function providerFromArbitraryBase() : \Generator { - foreach ($this->providerArbitraryBase() as [$base10, $alphabet, $baseN]) { + foreach (self::providerArbitraryBase() as [$base10, $alphabet, $baseN]) { yield [$base10, $alphabet, $baseN]; // test with a number of leading "zeros" @@ -3219,7 +3219,7 @@ public function testToArbitraryBase(string $base10, string $alphabet, string $ba self::assertSame($baseN, $actual); } - public function providerArbitraryBase() : array + public static function providerArbitraryBase() : array { $base7 = '0123456'; $base8 = '01234567'; @@ -3316,7 +3316,7 @@ public function testFromArbitraryBaseWithInvalidNumber(string $number, string $a BigInteger::fromArbitraryBase($number, $alphabet); } - public function providerFromArbitraryBaseWithInvalidNumber() : array + public static function providerFromArbitraryBaseWithInvalidNumber() : array { return [ ['', '01', 'The number cannot be empty.'], @@ -3345,7 +3345,7 @@ public function testToArbitraryBaseWithInvalidAlphabet(string $alphabet) : void $number->toArbitraryBase($alphabet); } - public function providerArbitraryBaseWithInvalidAlphabet() : array + public static function providerArbitraryBaseWithInvalidAlphabet() : array { return [ [''], @@ -3372,9 +3372,9 @@ public function testFromBytes(string $byteStringHex, bool $signed, string $expec self::assertSame($expectedNumber, (string) $number); } - public function providerFromBytes() : Generator + public static function providerFromBytes() : Generator { - foreach ($this->providerToBytes() as [$expectedNumber, $signed, $byteStringHex]) { + foreach (self::providerToBytes() as [$expectedNumber, $signed, $byteStringHex]) { yield [$byteStringHex, $signed, $expectedNumber]; // test with extra leading bits: these should return the same number @@ -3398,7 +3398,7 @@ public function testToBytes(string $number, bool $signed, string $expectedByteSt self::assertSame($expectedByteStringHex, strtoupper(bin2hex($byteString))); } - public function providerToBytes() : array + public static function providerToBytes() : array { return [ ['-549755813889', true, 'FF7FFFFFFFFF'], @@ -3617,7 +3617,7 @@ public function testRandomBits(int $numBits, string $randomBytesHex, string $exp self::assertBigIntegerEquals($expectedNumber, $actualNumber); } - public function providerRandomBits() : array + public static function providerRandomBits() : array { return [ [1, '00', '0'], @@ -3707,7 +3707,7 @@ public function testRandomRange(string $min, string $max, array $randomBytesHex, self::assertBigIntegerEquals($expectedNumber, $actualNumber); } - public function providerRandomRange() : array + public static function providerRandomRange() : array { return [ ['0', '1', ['00'], '0'], diff --git a/tests/BigNumberTest.php b/tests/BigNumberTest.php index efb6b67..b7b9656 100644 --- a/tests/BigNumberTest.php +++ b/tests/BigNumberTest.php @@ -32,7 +32,7 @@ public function testSum(array $values, string $expectedClass, string $expectedSu self::assertSame($expectedSum, (string) $sum); } - public function providerSum() : array + public static function providerSum() : array { return [ [[-1], BigInteger::class, '-1'], diff --git a/tests/BigRationalTest.php b/tests/BigRationalTest.php index 5ebb0c1..9b045e7 100644 --- a/tests/BigRationalTest.php +++ b/tests/BigRationalTest.php @@ -31,7 +31,7 @@ public function testNd(string $numerator, string $denominator, $n, $d) : void self::assertBigRationalInternalValues($numerator, $denominator, $rational); } - public function providerNd() : array + public static function providerNd() : array { return [ ['7', '1', '7', 1], @@ -61,7 +61,7 @@ public function testOf(string $numerator, string $denominator, string $string) : self::assertBigRationalInternalValues($numerator, $denominator, $rational); } - public function providerOf() : array + public static function providerOf() : array { return [ ['123', '456', '123/456'], @@ -93,7 +93,7 @@ public function testOfInvalidString(string $string) : void BigRational::of($string); } - public function providerOfInvalidString() : array + public static function providerOfInvalidString() : array { return [ ['123/-456'], @@ -145,7 +145,7 @@ public function testMin(array $values, string $min) : void self::assertBigRationalEquals($min, BigRational::min(... $values)); } - public function providerMin() : array + public static function providerMin() : array { return [ [['1/2', '1/4', '1/3'], '1/4'], @@ -172,7 +172,7 @@ public function testMax(array $values, string $max) : void self::assertBigRationalEquals($max, BigRational::max(... $values)); } - public function providerMax() : array + public static function providerMax() : array { return [ [['-5532146515641651651321321064580/32453', '-1/2', '-1/99'], '-1/99'], @@ -202,7 +202,7 @@ public function testSum(array $values, string $sum) : void self::assertBigRationalEquals($sum, BigRational::sum(... $values)); } - public function providerSum() : array + public static function providerSum() : array { return [ [['-5532146515641651651321321064580/32453', '-1/2', '-1/99'], '-1095365010097047026961621574064593/6425694'], @@ -241,7 +241,7 @@ public function testQuotientAndRemainder($rational, string $quotient, string $re self::assertBigIntegerEquals($remainder, $quotientAndRemainder[1]); } - public function providerQuotientAndRemainder() : array + public static function providerQuotientAndRemainder() : array { return [ ['1000/3', '333', '1'], @@ -263,7 +263,7 @@ public function testPlus(string $rational, $plus, string $expected) : void self::assertBigRationalEquals($expected, BigRational::of($rational)->plus($plus)); } - public function providerPlus() : array + public static function providerPlus() : array { return [ ['123/456', 1, '579/456'], @@ -288,7 +288,7 @@ public function testMinus(string $rational, string $minus, string $expected) : v self::assertBigRationalEquals($expected, BigRational::of($rational)->minus($minus)); } - public function providerMinus() : array + public static function providerMinus() : array { return [ ['123/456', '1', '-333/456'], @@ -311,7 +311,7 @@ public function testMultipliedBy(string $rational, string $minus, string $expect self::assertBigRationalEquals($expected, BigRational::of($rational)->multipliedBy($minus)); } - public function providerMultipliedBy() : array + public static function providerMultipliedBy() : array { return [ ['123/456', '1', '123/456'], @@ -336,7 +336,7 @@ public function testDividedBy(string $rational, string $minus, string $expected) self::assertBigRationalEquals($expected, BigRational::of($rational)->dividedBy($minus)); } - public function providerDividedBy() : array + public static function providerDividedBy() : array { return [ ['123/456', '1', '123/456'], @@ -361,7 +361,7 @@ public function testPower(string $number, int $exponent, string $expected) : voi self::assertBigRationalEquals($expected, BigRational::of($number)->power($exponent)); } - public function providerPower() : array + public static function providerPower() : array { return [ ['-3', 0, '1'], @@ -421,7 +421,7 @@ public function testReciprocal(string $rational, string $expected) : void self::assertBigRationalEquals($expected, BigRational::of($rational)->reciprocal()); } - public function providerReciprocal() : array + public static function providerReciprocal() : array { return [ ['1', '1'], @@ -450,7 +450,7 @@ public function testAbs(string $rational, string $expected) : void self::assertBigRationalEquals($expected, BigRational::of($rational)->abs()); } - public function providerAbs() : array + public static function providerAbs() : array { return [ ['0', '0'], @@ -473,7 +473,7 @@ public function testNegated(string $rational, string $expected) : void self::assertBigRationalEquals($expected, BigRational::of($rational)->negated()); } - public function providerNegated() : array + public static function providerNegated() : array { return [ ['0', '0'], @@ -497,7 +497,7 @@ public function testSimplified(string $rational, string $expected) : void self::assertBigRationalEquals($expected, BigRational::of($rational)->simplified()); } - public function providerSimplified() : array + public static function providerSimplified() : array { return [ ['0', '0'], @@ -588,7 +588,7 @@ public function testIsGreaterThanOrEqualTo(string $a, $b, int $cmp) : void self::assertSame($cmp >= 0, BigRational::of($a)->isGreaterThanOrEqualTo($b)); } - public function providerCompareTo() : array + public static function providerCompareTo() : array { return [ ['-1', '1/2', -1], @@ -685,7 +685,7 @@ public function testIsPositiveOrZero(string $number, int $sign) : void self::assertSame($sign >= 0, BigRational::of($number)->isPositiveOrZero()); } - public function providerSign() : array + public static function providerSign() : array { return [ ['0', 0], @@ -718,7 +718,7 @@ public function testToBigDecimal(string $number, ?string $expected) : void } } - public function providerToBigDecimal() : \Generator + public static function providerToBigDecimal() : \Generator { $tests = [ ['1', '1'], @@ -831,7 +831,7 @@ public function testToScale(string $number, int $scale, int $roundingMode, strin } } - public function providerToScale() : array + public static function providerToScale() : array { return [ ['1/8', 3, RoundingMode::UNNECESSARY, '0.125'], @@ -855,7 +855,7 @@ public function testToInt($rational, int $integer) : void self::assertSame($integer, BigRational::of($rational)->toInt()); } - public function providerToInt() : array + public static function providerToInt() : array { return [ [PHP_INT_MAX, PHP_INT_MAX], @@ -882,7 +882,7 @@ public function testToIntThrowsException(string $number) : void BigRational::of($number)->toInt(); } - public function providerToIntThrowsException() : array + public static function providerToIntThrowsException() : array { return [ ['-999999999999999999999999999999'], @@ -935,7 +935,7 @@ public function testToFloat(string $value, float $float) : void self::assertSame($float, BigRational::of($value)->toFloat()); } - public function providerToFloat() : array + public static function providerToFloat() : array { return [ ['0', 0.0], @@ -960,7 +960,7 @@ public function testToString(string $numerator, string $denominator, string $exp self::assertBigRationalEquals($expected, BigRational::nd($numerator, $denominator)); } - public function providerToString() : array + public static function providerToString() : array { return [ ['-1', '1', '-1'], diff --git a/tests/Internal/Calculator/NativeCalculatorTest.php b/tests/Internal/Calculator/NativeCalculatorTest.php index 245bdaa..da66764 100644 --- a/tests/Internal/Calculator/NativeCalculatorTest.php +++ b/tests/Internal/Calculator/NativeCalculatorTest.php @@ -21,7 +21,7 @@ public function testAdd(string $a, string $b, string $expectedValue) : void self::assertSame($expectedValue, $nativeCalculator->add($a, $b)); } - public function providerAdd() : array + public static function providerAdd() : array { return [ ['0', '1234567891234567889999999', '1234567891234567889999999'], @@ -43,7 +43,7 @@ public function testMul(string $a, string $b, string $expectedValue) : void self::assertSame($expectedValue, $nativeCalculator->mul($a, $b)); } - public function providerMul() : array + public static function providerMul() : array { return [ ['0', '0', '0'], @@ -70,7 +70,7 @@ public function testPow(string $a, int $b, string $expectedValue) : void self::assertSame($expectedValue, $nativeCalculator->pow($a, $b)); } - public function providerPow() : array + public static function providerPow() : array { return [ ['123456789012345678901234567890', 0, '1'], From 46be32602db754104bea854bcc0d430c8a396cf3 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Tue, 1 Aug 2023 12:04:23 +0200 Subject: [PATCH 06/16] Convert RoundingMode to Enum --- CHANGELOG.md | 1 + README.md | 2 +- src/BigDecimal.php | 6 ++-- src/BigInteger.php | 6 ++-- src/BigNumber.php | 6 ++-- src/BigRational.php | 2 +- src/Internal/Calculator.php | 8 ++--- src/RoundingMode.php | 31 +++++++------------- tests/BigDecimalTest.php | 58 +++++++++++++++++-------------------- tests/BigIntegerTest.php | 32 +++++++++----------- tests/BigRationalTest.php | 7 +---- 11 files changed, 67 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f52569f..324fc10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. 💥 **Breaking changes** - Minimum PHP version is now 8.1 +- `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now ## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16 diff --git a/README.md b/README.md index 0c214ce..baa28b4 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ This library provides the following public classes in the `Brick\Math` namespace - [BigInteger](https://github.com/brick/math/blob/0.12.0/src/BigInteger.php): represents an arbitrary-precision integer number. - [BigDecimal](https://github.com/brick/math/blob/0.12.0/src/BigDecimal.php): represents an arbitrary-precision decimal number. - [BigRational](https://github.com/brick/math/blob/0.12.0/src/BigRational.php): represents an arbitrary-precision rational number (fraction). -- [RoundingMode](https://github.com/brick/math/blob/0.12.0/src/RoundingMode.php): holds constants for the rounding modes. +- [RoundingMode](https://github.com/brick/math/blob/0.12.0/src/RoundingMode.php): enum representing all available rounding modes. And the following exceptions in the `Brick\Math\Exception` namespace: diff --git a/src/BigDecimal.php b/src/BigDecimal.php index 614a7e6..2c89e15 100644 --- a/src/BigDecimal.php +++ b/src/BigDecimal.php @@ -223,12 +223,12 @@ public function multipliedBy(BigNumber|int|float|string $that) : BigDecimal * * @param BigNumber|int|float|string $that The divisor. * @param int|null $scale The desired scale, or null to use the scale of this number. - * @param int $roundingMode An optional rounding mode. + * @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY. * * @throws \InvalidArgumentException If the scale or rounding mode is invalid. * @throws MathException If the number is invalid, is zero, or rounding was necessary. */ - public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal { $that = BigDecimal::of($that); @@ -631,7 +631,7 @@ public function toBigRational() : BigRational return self::newBigRational($numerator, $denominator, false); } - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal { if ($scale === $this->scale) { return $this; diff --git a/src/BigInteger.php b/src/BigInteger.php index 4356793..6ee8fa4 100644 --- a/src/BigInteger.php +++ b/src/BigInteger.php @@ -429,12 +429,12 @@ public function multipliedBy(BigNumber|int|float|string $that) : BigInteger * Returns the result of the division of this number by the given one. * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. - * @param int $roundingMode An optional rounding mode. + * @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY. * * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero, * or RoundingMode::UNNECESSARY is used and the remainder is not zero. */ - public function dividedBy(BigNumber|int|float|string $that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger + public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigInteger { $that = BigInteger::of($that); @@ -888,7 +888,7 @@ public function toBigRational() : BigRational return self::newBigRational($this, BigInteger::one(), false); } - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal { return $this->toBigDecimal()->toScale($scale, $roundingMode); } diff --git a/src/BigNumber.php b/src/BigNumber.php index 1161676..7de3216 100644 --- a/src/BigNumber.php +++ b/src/BigNumber.php @@ -454,13 +454,13 @@ 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`. - * @param int $roundingMode A `RoundingMode` constant. + * @param int $scale The scale of the resulting `BigDecimal`. + * @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY. * * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding. * This only applies when RoundingMode::UNNECESSARY is used. */ - abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal; + abstract public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal; /** * Returns the exact value of this number as a native integer. diff --git a/src/BigRational.php b/src/BigRational.php index 31f2904..548ae33 100644 --- a/src/BigRational.php +++ b/src/BigRational.php @@ -353,7 +353,7 @@ public function toBigRational() : BigRational return $this; } - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal { return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode); } diff --git a/src/Internal/Calculator.php b/src/Internal/Calculator.php index fb8e06f..44dd669 100644 --- a/src/Internal/Calculator.php +++ b/src/Internal/Calculator.php @@ -430,16 +430,16 @@ final public function toArbitraryBase(string $number, string $alphabet, int $bas * * Rounding is performed when the remainder of the division is not zero. * - * @param string $a The dividend. - * @param string $b The divisor, must not be zero. - * @param int $roundingMode The rounding mode. + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * @param RoundingMode $roundingMode The rounding mode. * * @throws \InvalidArgumentException If the rounding mode is invalid. * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary. * * @psalm-suppress ImpureFunctionCall */ - final public function divRound(string $a, string $b, int $roundingMode) : string + final public function divRound(string $a, string $b, RoundingMode $roundingMode) : string { [$quotient, $remainder] = $this->divQR($a, $b); diff --git a/src/RoundingMode.php b/src/RoundingMode.php index 06936d8..e8ee6a8 100644 --- a/src/RoundingMode.php +++ b/src/RoundingMode.php @@ -13,24 +13,15 @@ * regardless the digits' contribution to the value of the number. In other words, considered * as a numerical value, the discarded fraction could have an absolute value greater than one. */ -final class RoundingMode +enum RoundingMode { - /** - * Private constructor. This class is not instantiable. - * - * @codeCoverageIgnore - */ - private function __construct() - { - } - /** * Asserts that the requested operation has an exact result, hence no rounding is necessary. * * If this rounding mode is specified on an operation that yields a result that * cannot be represented at the requested scale, a RoundingNecessaryException is thrown. */ - public const UNNECESSARY = 0; + case UNNECESSARY; /** * Rounds away from zero. @@ -38,7 +29,7 @@ private function __construct() * Always increments the digit prior to a nonzero discarded fraction. * Note that this rounding mode never decreases the magnitude of the calculated value. */ - public const UP = 1; + case UP; /** * Rounds towards zero. @@ -46,7 +37,7 @@ private function __construct() * Never increments the digit prior to a discarded fraction (i.e., truncates). * Note that this rounding mode never increases the magnitude of the calculated value. */ - public const DOWN = 2; + case DOWN; /** * Rounds towards positive infinity. @@ -54,7 +45,7 @@ private function __construct() * If the result is positive, behaves as for UP; if negative, behaves as for DOWN. * Note that this rounding mode never decreases the calculated value. */ - public const CEILING = 3; + case CEILING; /** * Rounds towards negative infinity. @@ -62,7 +53,7 @@ private function __construct() * If the result is positive, behave as for DOWN; if negative, behave as for UP. * Note that this rounding mode never increases the calculated value. */ - public const FLOOR = 4; + case FLOOR; /** * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up. @@ -70,28 +61,28 @@ private function __construct() * Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN. * Note that this is the rounding mode commonly taught at school. */ - public const HALF_UP = 5; + case HALF_UP; /** * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down. * * Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN. */ - public const HALF_DOWN = 6; + case HALF_DOWN; /** * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity. * * If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN. */ - public const HALF_CEILING = 7; + case HALF_CEILING; /** * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity. * * If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP. */ - public const HALF_FLOOR = 8; + case HALF_FLOOR; /** * Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor. @@ -103,5 +94,5 @@ private function __construct() * cumulative error when applied repeatedly over a sequence of calculations. * It is sometimes known as "Banker's rounding", and is chiefly used in the USA. */ - public const HALF_EVEN = 9; + case HALF_EVEN; } diff --git a/tests/BigDecimalTest.php b/tests/BigDecimalTest.php index 700d4c4..261c874 100644 --- a/tests/BigDecimalTest.php +++ b/tests/BigDecimalTest.php @@ -726,14 +726,14 @@ public static function providerMultipliedBy() : array /** * @dataProvider providerDividedBy * - * @param string $a The base number. - * @param string $b The number to divide. - * @param int|null $scale The desired scale of the result. - * @param int $roundingMode The rounding mode. - * @param string $unscaledValue The expected unscaled value of the result. - * @param int $expectedScale The expected scale of the result. + * @param string $a The base number. + * @param string $b The number to divide. + * @param int|null $scale The desired scale of the result. + * @param RoundingMode $roundingMode The rounding mode. + * @param string $unscaledValue The expected unscaled value of the result. + * @param int $expectedScale The expected scale of the result. */ - public function testDividedBy(string $a, string $b, ?int $scale, int $roundingMode, string $unscaledValue, int $expectedScale) : void + public function testDividedBy(string $a, string $b, ?int $scale, RoundingMode $roundingMode, string $unscaledValue, int $expectedScale) : void { $decimal = BigDecimal::of($a)->dividedBy($b, $scale, $roundingMode); self::assertBigDecimalInternalValues($unscaledValue, $expectedScale, $decimal); @@ -875,22 +875,16 @@ public function testDividedByWithNegativeScaleThrowsException() : void BigDecimal::of(1)->dividedBy(2, -1); } - public function testDividedByWithInvalidRoundingModeThrowsException() : void - { - $this->expectException(\InvalidArgumentException::class); - BigDecimal::of(1)->dividedBy(2, 0, -1); - } - /** * @dataProvider providerRoundingMode * - * @param int $roundingMode The rounding mode. - * @param string $number The number to round. - * @param string|null $two The expected rounding to a scale of two, or null if an exception is expected. - * @param string|null $one The expected rounding to a scale of one, or null if an exception is expected. - * @param string|null $zero The expected rounding to a scale of zero, or null if an exception is expected. + * @param RoundingMode $roundingMode The rounding mode. + * @param string $number The number to round. + * @param string|null $two The expected rounding to a scale of two, or null if an exception is expected. + * @param string|null $one The expected rounding to a scale of one, or null if an exception is expected. + * @param string|null $zero The expected rounding to a scale of zero, or null if an exception is expected. */ - public function testRoundingMode(int $roundingMode, string $number, ?string $two, ?string $one, ?string $zero) : void + public function testRoundingMode(RoundingMode $roundingMode, string $number, ?string $two, ?string $one, ?string $zero) : void { $number = BigDecimal::of($number); @@ -899,14 +893,14 @@ public function testRoundingMode(int $roundingMode, string $number, ?string $two } /** - * @param int $roundingMode The rounding mode. - * @param BigDecimal $number The number to round. - * @param string $divisor The divisor. - * @param string|null $two The expected rounding to a scale of two, or null if an exception is expected. - * @param string|null $one The expected rounding to a scale of one, or null if an exception is expected. - * @param string|null $zero The expected rounding to a scale of zero, or null if an exception is expected. + * @param RoundingMode $roundingMode The rounding mode. + * @param BigDecimal $number The number to round. + * @param string $divisor The divisor. + * @param string|null $two The expected rounding to a scale of two, or null if an exception is expected. + * @param string|null $one The expected rounding to a scale of one, or null if an exception is expected. + * @param string|null $zero The expected rounding to a scale of zero, or null if an exception is expected. */ - private function doTestRoundingMode(int $roundingMode, BigDecimal $number, string $divisor, ?string $two, ?string $one, ?string $zero) : void + private function doTestRoundingMode(RoundingMode $roundingMode, BigDecimal $number, string $divisor, ?string $two, ?string $one, ?string $zero) : void { foreach ([$zero, $one, $two] as $scale => $expected) { if ($expected === null) { @@ -1799,13 +1793,13 @@ public static function providerPowerWithInvalidExponentThrowsException() : array /** * @dataProvider providerToScale * - * @param string $number The number to scale. - * @param int $toScale The scale to apply. - * @param int $roundingMode The rounding mode to apply. - * @param string $unscaledValue The expected unscaled value of the result. - * @param int $scale The expected scale of the result. + * @param string $number The number to scale. + * @param int $toScale The scale to apply. + * @param RoundingMode $roundingMode The rounding mode to apply. + * @param string $unscaledValue The expected unscaled value of the result. + * @param int $scale The expected scale of the result. */ - public function testToScale(string $number, int $toScale, int $roundingMode, string $unscaledValue, int $scale) : void + public function testToScale(string $number, int $toScale, RoundingMode $roundingMode, string $unscaledValue, int $scale) : void { $decimal = BigDecimal::of($number)->toScale($toScale, $roundingMode); self::assertBigDecimalInternalValues($unscaledValue, $scale, $decimal); diff --git a/tests/BigIntegerTest.php b/tests/BigIntegerTest.php index 54e9301..070adac 100644 --- a/tests/BigIntegerTest.php +++ b/tests/BigIntegerTest.php @@ -660,22 +660,16 @@ public static function providerDividedBy() : array ]; } - public function testDividedByWithInvalidRoundingModeThrowsException() : void - { - $this->expectException(\InvalidArgumentException::class); - BigInteger::of(1)->dividedBy(2, -1); - } - /** * @dataProvider providerDividedByWithRoundingMode * - * @param int $roundingMode The rounding mode. - * @param string $number The number to round. - * @param string|null $ten The expected rounding divided by 10, or null if an exception is expected. - * @param string|null $hundred The expected rounding divided by 100 or null if an exception is expected. - * @param string|null $thousand The expected rounding divided by 1000, or null if an exception is expected. + * @param RoundingMode $roundingMode The rounding mode. + * @param string $number The number to round. + * @param string|null $ten The expected rounding divided by 10, or null if an exception is expected. + * @param string|null $hundred The expected rounding divided by 100 or null if an exception is expected. + * @param string|null $thousand The expected rounding divided by 1000, or null if an exception is expected. */ - public function testDividedByWithRoundingMode(int $roundingMode, string $number, ?string $ten, ?string $hundred, ?string $thousand) : void + public function testDividedByWithRoundingMode(RoundingMode $roundingMode, string $number, ?string $ten, ?string $hundred, ?string $thousand) : void { $number = BigInteger::of($number); @@ -684,14 +678,14 @@ public function testDividedByWithRoundingMode(int $roundingMode, string $number, } /** - * @param int $roundingMode The rounding mode. - * @param BigInteger $number The number to round. - * @param string $divisor The divisor. - * @param string|null $ten The expected rounding to a scale of two, or null if an exception is expected. - * @param string|null $hundred The expected rounding to a scale of one, or null if an exception is expected. - * @param string|null $thousand The expected rounding to a scale of zero, or null if an exception is expected. + * @param RoundingMode $roundingMode The rounding mode. + * @param BigInteger $number The number to round. + * @param string $divisor The divisor. + * @param string|null $ten The expected rounding to a scale of two, or null if an exception is expected. + * @param string|null $hundred The expected rounding to a scale of one, or null if an exception is expected. + * @param string|null $thousand The expected rounding to a scale of zero, or null if an exception is expected. */ - private function doTestDividedByWithRoundingMode(int $roundingMode, BigInteger $number, string $divisor, ?string $ten, ?string $hundred, ?string $thousand) : void + private function doTestDividedByWithRoundingMode(RoundingMode $roundingMode, BigInteger $number, string $divisor, ?string $ten, ?string $hundred, ?string $thousand) : void { foreach ([$ten, $hundred, $thousand] as $expected) { $divisor .= '0'; diff --git a/tests/BigRationalTest.php b/tests/BigRationalTest.php index 9b045e7..db2c3ef 100644 --- a/tests/BigRationalTest.php +++ b/tests/BigRationalTest.php @@ -810,13 +810,8 @@ public static function providerToBigDecimal() : \Generator /** * @dataProvider providerToScale - * - * @param string $number - * @param int $scale - * @param int $roundingMode - * @param string $expected */ - public function testToScale(string $number, int $scale, int $roundingMode, string $expected) : void + public function testToScale(string $number, int $scale, RoundingMode $roundingMode, string $expected) : void { $number = BigRational::of($number); From e9883ae558f16357ca5da5c10d5776b49eaff873 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Tue, 1 Aug 2023 13:24:05 +0200 Subject: [PATCH 07/16] Readonly properties --- random-tests.php | 8 ++++---- src/BigDecimal.php | 4 ++-- src/BigInteger.php | 2 +- src/BigRational.php | 4 ++-- src/Internal/Calculator/NativeCalculator.php | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/random-tests.php b/random-tests.php index 10df4fa..67c80fe 100644 --- a/random-tests.php +++ b/random-tests.php @@ -12,9 +12,9 @@ use Brick\Math\Internal\Calculator; (new class(30) { // max digits - private Calculator\GmpCalculator $gmp; - private Calculator\BcMathCalculator $bcmath; - private Calculator\NativeCalculator $native; + private readonly Calculator\GmpCalculator $gmp; + private readonly Calculator\BcMathCalculator $bcmath; + private readonly Calculator\NativeCalculator $native; private int $testCounter = 0; private float $lastOutputTime = 0.0; @@ -23,7 +23,7 @@ private int $testsPerSecond = 0; public function __construct( - private int $maxDigits, + private readonly int $maxDigits, ) { $this->gmp = new Calculator\GmpCalculator(); $this->bcmath = new Calculator\BcMathCalculator(); diff --git a/src/BigDecimal.php b/src/BigDecimal.php index 2c89e15..10807ce 100644 --- a/src/BigDecimal.php +++ b/src/BigDecimal.php @@ -23,14 +23,14 @@ final class BigDecimal extends BigNumber * No leading zero must be present. * No leading minus sign must be present if the value is 0. */ - private string $value; + private readonly string $value; /** * The scale (number of digits after the decimal point) of this decimal number. * * This must be zero or more. */ - private int $scale; + private readonly int $scale; /** * Protected constructor. Use a factory method to obtain an instance. diff --git a/src/BigInteger.php b/src/BigInteger.php index 6ee8fa4..5bba58b 100644 --- a/src/BigInteger.php +++ b/src/BigInteger.php @@ -27,7 +27,7 @@ final class BigInteger extends BigNumber * No leading zeros must be present. * No leading minus sign must be present if the number is zero. */ - private string $value; + private readonly string $value; /** * Protected constructor. Use a factory method to obtain an instance. diff --git a/src/BigRational.php b/src/BigRational.php index 548ae33..2eaec50 100644 --- a/src/BigRational.php +++ b/src/BigRational.php @@ -21,12 +21,12 @@ final class BigRational extends BigNumber /** * The numerator. */ - private BigInteger $numerator; + private readonly BigInteger $numerator; /** * The denominator. Always strictly positive. */ - private BigInteger $denominator; + private readonly BigInteger $denominator; /** * Protected constructor. Use a factory method to obtain an instance. diff --git a/src/Internal/Calculator/NativeCalculator.php b/src/Internal/Calculator/NativeCalculator.php index 70a5159..6acd063 100644 --- a/src/Internal/Calculator/NativeCalculator.php +++ b/src/Internal/Calculator/NativeCalculator.php @@ -23,7 +23,7 @@ class NativeCalculator extends Calculator * Example: 32-bit: max number 1,999,999,999 (9 digits + carry) * 64-bit: max number 1,999,999,999,999,999,999 (18 digits + carry) */ - private int $maxDigits; + private readonly int $maxDigits; /** * @codeCoverageIgnore From d83b16aa6aa3488b9e9bb37715842c2d66b5e70b Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Tue, 1 Aug 2023 13:25:43 +0200 Subject: [PATCH 08/16] First class callable syntax --- src/BigInteger.php | 3 ++- tests/BigIntegerTest.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/BigInteger.php b/src/BigInteger.php index 5bba58b..e173d77 100644 --- a/src/BigInteger.php +++ b/src/BigInteger.php @@ -225,9 +225,10 @@ public static function randomBits(int $numBits, ?callable $randomBytesGenerator } if ($randomBytesGenerator === null) { - $randomBytesGenerator = 'random_bytes'; + $randomBytesGenerator = random_bytes(...); } + /** @var int<1, max> $byteLength */ $byteLength = \intdiv($numBits - 1, 8) + 1; $extraBits = ($byteLength * 8 - $numBits); diff --git a/tests/BigIntegerTest.php b/tests/BigIntegerTest.php index 070adac..87184a8 100644 --- a/tests/BigIntegerTest.php +++ b/tests/BigIntegerTest.php @@ -381,7 +381,7 @@ public function testTen() : void */ public function testGcdMultiple(array $values, string $expectedGCD): void { - $values = array_map(fn (string $value) => BigInteger::of($value), $values); + $values = array_map(BigInteger::of(...), $values); $actualGCD = BigInteger::gcdMultiple(...$values); self::assertSame($expectedGCD, (string) $actualGCD); From d341c0b66ec17c5c8ec78ad255252e8bdafdd1f5 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Tue, 1 Aug 2023 13:28:40 +0200 Subject: [PATCH 09/16] Never return type --- random-tests.php | 2 +- src/BigNumber.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/random-tests.php b/random-tests.php index 67c80fe..37f955d 100644 --- a/random-tests.php +++ b/random-tests.php @@ -132,7 +132,7 @@ private function test(string $test, Closure $callback) : void * @param string $c2 The name of the second calculator. * @param string $test A string representing the test being executed. */ - private function failure(string $c1, string $c2, string $test) : void + private function failure(string $c1, string $c2, string $test) : never { echo PHP_EOL; echo 'FAILURE!', PHP_EOL; diff --git a/src/BigNumber.php b/src/BigNumber.php index 7de3216..60176f6 100644 --- a/src/BigNumber.php +++ b/src/BigNumber.php @@ -67,7 +67,7 @@ public static function of(BigNumber|int|float|string $value) : BigNumber $value = (string) $value; } - $throw = static function() use ($value) : void { + $throw = static function() use ($value) : never { throw new NumberFormatException(\sprintf( 'The given value "%s" does not represent a valid number.', $value From fe462b3dd5c70aa02486611642a8da9995f7c8c0 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Sat, 5 Aug 2023 11:56:19 +0200 Subject: [PATCH 10/16] Use env vars for PHP versions --- .github/workflows/ci.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9fcbb0..c185baf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,10 @@ on: push: pull_request: +env: + PSALM_PHP_VERSION: "8.2" + COVERAGE_PHP_VERSION: "8.2" + jobs: psalm: name: Psalm @@ -16,7 +20,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: "8.2" + php-version: ${{ env.PSALM_PHP_VERSION }} - name: Install composer dependencies uses: "ramsey/composer-install@v1" @@ -56,7 +60,7 @@ jobs: run: vendor/bin/phpunit env: CALCULATOR: ${{ matrix.calculator }} - if: ${{ matrix.php-version != '8.2' }} + if: ${{ matrix.php-version != env.COVERAGE_PHP_VERSION }} - name: Run PHPUnit with coverage run: | @@ -64,7 +68,7 @@ jobs: vendor/bin/phpunit --coverage-clover build/logs/clover.xml env: CALCULATOR: ${{ matrix.calculator }} - if: ${{ matrix.php-version == '8.2' }} + if: ${{ matrix.php-version == env.COVERAGE_PHP_VERSION }} - name: Run PHPUnit with bcscale() run: vendor/bin/phpunit @@ -77,4 +81,4 @@ jobs: run: vendor/bin/php-coveralls --coverage_clover=build/logs/clover.xml -v env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: ${{ matrix.php-version == '8.2' }} + if: ${{ matrix.php-version == env.COVERAGE_PHP_VERSION }} From e8b2e8f2cda7274d8f32597e8d2f134157fbfaa4 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Thu, 10 Aug 2023 00:45:39 +0200 Subject: [PATCH 11/16] Remove Serializable See: - https://wiki.php.net/rfc/custom_object_serialization - https://wiki.php.net/rfc/phase_out_serializable --- CHANGELOG.md | 1 + src/BigDecimal.php | 30 ------------------------------ src/BigInteger.php | 27 --------------------------- src/BigNumber.php | 2 +- src/BigRational.php | 30 ------------------------------ tests/BigDecimalTest.php | 2 +- tests/BigIntegerTest.php | 2 +- tests/BigRationalTest.php | 2 +- 8 files changed, 5 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 324fc10..27dfef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Minimum PHP version is now 8.1 - `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now +- `BigNumber` classes do not implement the `Serializable` interface anymore (they use the [new custom object serialization mechanism](https://wiki.php.net/rfc/custom_object_serialization)) ## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16 diff --git a/src/BigDecimal.php b/src/BigDecimal.php index 10807ce..fdba20c 100644 --- a/src/BigDecimal.php +++ b/src/BigDecimal.php @@ -693,36 +693,6 @@ public function __unserialize(array $data): void $this->scale = $data['scale']; } - /** - * This method is required by interface Serializable and SHOULD NOT be accessed directly. - * - * @internal - */ - public function serialize() : string - { - return $this->value . ':' . $this->scale; - } - - /** - * This method is only here to implement interface Serializable and cannot be accessed directly. - * - * @internal - * @psalm-suppress RedundantPropertyInitializationCheck - * - * @throws \LogicException - */ - public function unserialize($value) : void - { - if (isset($this->value)) { - throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); - } - - [$value, $scale] = \explode(':', $value); - - $this->value = $value; - $this->scale = (int) $scale; - } - /** * Puts the internal values of the given decimal numbers on the same scale. * diff --git a/src/BigInteger.php b/src/BigInteger.php index e173d77..c39335b 100644 --- a/src/BigInteger.php +++ b/src/BigInteger.php @@ -1050,31 +1050,4 @@ public function __unserialize(array $data): void $this->value = $data['value']; } - - /** - * This method is required by interface Serializable and SHOULD NOT be accessed directly. - * - * @internal - */ - public function serialize() : string - { - return $this->value; - } - - /** - * This method is only here to implement interface Serializable and cannot be accessed directly. - * - * @internal - * @psalm-suppress RedundantPropertyInitializationCheck - * - * @throws \LogicException - */ - public function unserialize($value) : void - { - if (isset($this->value)) { - throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); - } - - $this->value = $value; - } } diff --git a/src/BigNumber.php b/src/BigNumber.php index 60176f6..340fff3 100644 --- a/src/BigNumber.php +++ b/src/BigNumber.php @@ -14,7 +14,7 @@ * * @psalm-immutable */ -abstract class BigNumber implements \Serializable, \JsonSerializable +abstract class BigNumber implements \JsonSerializable { /** * The regular expression used to parse integer, decimal and rational numbers. diff --git a/src/BigRational.php b/src/BigRational.php index 2eaec50..65caeb0 100644 --- a/src/BigRational.php +++ b/src/BigRational.php @@ -412,34 +412,4 @@ public function __unserialize(array $data): void $this->numerator = $data['numerator']; $this->denominator = $data['denominator']; } - - /** - * This method is required by interface Serializable and SHOULD NOT be accessed directly. - * - * @internal - */ - public function serialize() : string - { - return $this->numerator . '/' . $this->denominator; - } - - /** - * This method is only here to implement interface Serializable and cannot be accessed directly. - * - * @internal - * @psalm-suppress RedundantPropertyInitializationCheck - * - * @throws \LogicException - */ - public function unserialize($value) : void - { - if (isset($this->numerator)) { - throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); - } - - [$numerator, $denominator] = \explode('/', $value); - - $this->numerator = BigInteger::of($numerator); - $this->denominator = BigInteger::of($denominator); - } } diff --git a/tests/BigDecimalTest.php b/tests/BigDecimalTest.php index 261c874..ef6ba27 100644 --- a/tests/BigDecimalTest.php +++ b/tests/BigDecimalTest.php @@ -2585,6 +2585,6 @@ public function testSerialize() : void public function testDirectCallToUnserialize() : void { $this->expectException(\LogicException::class); - BigDecimal::zero()->unserialize('123:0'); + BigDecimal::zero()->__unserialize([]); } } diff --git a/tests/BigIntegerTest.php b/tests/BigIntegerTest.php index 87184a8..ca67514 100644 --- a/tests/BigIntegerTest.php +++ b/tests/BigIntegerTest.php @@ -3762,7 +3762,7 @@ public function testSerialize() : void public function testDirectCallToUnserialize() : void { $this->expectException(\LogicException::class); - BigInteger::zero()->unserialize('123'); + BigInteger::zero()->__unserialize([]); } public function testJsonSerialize() : void diff --git a/tests/BigRationalTest.php b/tests/BigRationalTest.php index db2c3ef..8e39d0a 100644 --- a/tests/BigRationalTest.php +++ b/tests/BigRationalTest.php @@ -983,6 +983,6 @@ public function testSerialize() : void public function testDirectCallToUnserialize() : void { $this->expectException(\LogicException::class); - BigRational::nd(1, 2)->unserialize('123/456'); + BigRational::nd(1, 2)->__unserialize([]); } } From 336ee953c0d55b72b41507d123300cf2959dfe60 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Fri, 11 Aug 2023 12:40:07 +0200 Subject: [PATCH 12/16] Test on lowest dependencies --- .github/workflows/ci.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c185baf..07db883 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,18 @@ jobs: - GMP - BCMath - Native + deps: + - "highest" + include: + - php-version: "8.1" + calculator: GMP + deps: "lowest" + - php-version: "8.1" + calculator: BCMath + deps: "lowest" + - php-version: "8.1" + calculator: Native + deps: "lowest" steps: - name: Checkout @@ -55,6 +67,8 @@ jobs: - name: Install composer dependencies uses: "ramsey/composer-install@v1" + with: + dependency-versions: ${{ matrix.deps }} - name: Run PHPUnit run: vendor/bin/phpunit From 96bdecbd0edb04f459943fb96f410f22a64359db Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Mon, 30 Oct 2023 23:32:45 +0100 Subject: [PATCH 13/16] Change BigNumber::of() return type to static --- CHANGELOG.md | 3 +++ src/BigDecimal.php | 8 ++------ src/BigInteger.php | 8 ++------ src/BigNumber.php | 32 +++++++++++++++++++++++++++----- src/BigRational.php | 8 ++------ 5 files changed, 36 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27dfef2..2125bd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ All notable changes to this project will be documented in this file. - Minimum PHP version is now 8.1 - `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now - `BigNumber` classes do not implement the `Serializable` interface anymore (they use the [new custom object serialization mechanism](https://wiki.php.net/rfc/custom_object_serialization)) +- The following breaking changes only affect you if you're creating your own `BigNumber` subclasses: + - the return type of `BigNumber::of()` is now `static` + - `BigNumber` has a new abstract method `from()` ## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16 diff --git a/src/BigDecimal.php b/src/BigDecimal.php index fdba20c..021ba7f 100644 --- a/src/BigDecimal.php +++ b/src/BigDecimal.php @@ -45,15 +45,11 @@ protected function __construct(string $value, int $scale = 0) } /** - * Creates a BigDecimal of the given value. - * - * @throws MathException If the value cannot be converted to a BigDecimal. - * * @psalm-pure */ - public static function of(BigNumber|int|float|string $value) : BigDecimal + protected static function from(BigNumber $number): static { - return parent::of($value)->toBigDecimal(); + return $number->toBigDecimal(); } /** diff --git a/src/BigInteger.php b/src/BigInteger.php index c39335b..fd23420 100644 --- a/src/BigInteger.php +++ b/src/BigInteger.php @@ -40,15 +40,11 @@ protected function __construct(string $value) } /** - * Creates a BigInteger of the given value. - * - * @throws MathException If the value cannot be converted to a BigInteger. - * * @psalm-pure */ - public static function of(BigNumber|int|float|string $value) : BigInteger + protected static function from(BigNumber $number): static { - return parent::of($value)->toBigInteger(); + return $number->toBigInteger(); } /** diff --git a/src/BigNumber.php b/src/BigNumber.php index 340fff3..b7f6779 100644 --- a/src/BigNumber.php +++ b/src/BigNumber.php @@ -53,7 +53,24 @@ abstract class BigNumber implements \JsonSerializable * * @psalm-pure */ - public static function of(BigNumber|int|float|string $value) : BigNumber + public static function of(BigNumber|int|float|string $value) : static + { + $value = self::_of($value); + + if (static::class === BigNumber::class) { + // https://github.com/vimeo/psalm/issues/10309 + assert($value instanceof static); + + return $value; + } + + return static::from($value); + } + + /** + * @psalm-pure + */ + private static function _of(BigNumber|int|float|string $value) : BigNumber { if ($value instanceof BigNumber) { return $value; @@ -145,6 +162,15 @@ public static function of(BigNumber|int|float|string $value) : BigNumber return new BigInteger($integral); } + /** + * Overridden by subclasses to convert a BigNumber to an instance of the subclass. + * + * @throws MathException If the value cannot be converted. + * + * @psalm-pure + */ + abstract protected static function from(BigNumber $number): static; + /** * Proxy method to access BigInteger's protected constructor from sibling classes. * @@ -187,8 +213,6 @@ protected function newBigRational(BigInteger $numerator, BigInteger $denominator * @throws \InvalidArgumentException If no values are given. * @throws MathException If an argument is not valid. * - * @psalm-suppress LessSpecificReturnStatement - * @psalm-suppress MoreSpecificReturnType * @psalm-pure */ public static function min(BigNumber|int|float|string ...$values) : static @@ -219,8 +243,6 @@ public static function min(BigNumber|int|float|string ...$values) : static * @throws \InvalidArgumentException If no values are given. * @throws MathException If an argument is not valid. * - * @psalm-suppress LessSpecificReturnStatement - * @psalm-suppress MoreSpecificReturnType * @psalm-pure */ public static function max(BigNumber|int|float|string ...$values) : static diff --git a/src/BigRational.php b/src/BigRational.php index 65caeb0..9e07215 100644 --- a/src/BigRational.php +++ b/src/BigRational.php @@ -55,15 +55,11 @@ protected function __construct(BigInteger $numerator, BigInteger $denominator, b } /** - * Creates a BigRational of the given value. - * - * @throws MathException If the value cannot be converted to a BigRational. - * * @psalm-pure */ - public static function of(BigNumber|int|float|string $value) : BigRational + protected static function from(BigNumber $number): static { - return parent::of($value)->toBigRational(); + return $number->toBigRational(); } /** From 70843ed65276623e8d011397819b7f273690b97b Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Mon, 30 Oct 2023 23:37:43 +0100 Subject: [PATCH 14/16] Final BigNumber public/protected methods --- CHANGELOG.md | 1 + src/BigNumber.php | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2125bd9..31e80ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - The following breaking changes only affect you if you're creating your own `BigNumber` subclasses: - the return type of `BigNumber::of()` is now `static` - `BigNumber` has a new abstract method `from()` + - all `public` and `protected` functions of `BigNumber` are now `final` ## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16 diff --git a/src/BigNumber.php b/src/BigNumber.php index b7f6779..578283b 100644 --- a/src/BigNumber.php +++ b/src/BigNumber.php @@ -53,7 +53,7 @@ abstract class BigNumber implements \JsonSerializable * * @psalm-pure */ - public static function of(BigNumber|int|float|string $value) : static + final public static function of(BigNumber|int|float|string $value) : static { $value = self::_of($value); @@ -177,7 +177,7 @@ abstract protected static function from(BigNumber $number): static; * @internal * @psalm-pure */ - protected function newBigInteger(string $value) : BigInteger + final protected function newBigInteger(string $value) : BigInteger { return new BigInteger($value); } @@ -188,7 +188,7 @@ protected function newBigInteger(string $value) : BigInteger * @internal * @psalm-pure */ - protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal + final protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal { return new BigDecimal($value, $scale); } @@ -199,7 +199,7 @@ protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal * @internal * @psalm-pure */ - protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational + final protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational { return new BigRational($numerator, $denominator, $checkDenominator); } @@ -215,7 +215,7 @@ protected function newBigRational(BigInteger $numerator, BigInteger $denominator * * @psalm-pure */ - public static function min(BigNumber|int|float|string ...$values) : static + final public static function min(BigNumber|int|float|string ...$values) : static { $min = null; @@ -245,7 +245,7 @@ public static function min(BigNumber|int|float|string ...$values) : static * * @psalm-pure */ - public static function max(BigNumber|int|float|string ...$values) : static + final public static function max(BigNumber|int|float|string ...$values) : static { $max = null; @@ -275,7 +275,7 @@ public static function max(BigNumber|int|float|string ...$values) : static * * @psalm-pure */ - public static function sum(BigNumber|int|float|string ...$values) : static + final public static function sum(BigNumber|int|float|string ...$values) : static { /** @var static|null $sum */ $sum = null; @@ -357,7 +357,7 @@ private static function cleanUp(string $number) : string /** * Checks if this number is equal to the given one. */ - public function isEqualTo(BigNumber|int|float|string $that) : bool + final public function isEqualTo(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) === 0; } @@ -365,7 +365,7 @@ public function isEqualTo(BigNumber|int|float|string $that) : bool /** * Checks if this number is strictly lower than the given one. */ - public function isLessThan(BigNumber|int|float|string $that) : bool + final public function isLessThan(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) < 0; } @@ -373,7 +373,7 @@ public function isLessThan(BigNumber|int|float|string $that) : bool /** * Checks if this number is lower than or equal to the given one. */ - public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool + final public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) <= 0; } @@ -381,7 +381,7 @@ public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool /** * Checks if this number is strictly greater than the given one. */ - public function isGreaterThan(BigNumber|int|float|string $that) : bool + final public function isGreaterThan(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) > 0; } @@ -389,7 +389,7 @@ public function isGreaterThan(BigNumber|int|float|string $that) : bool /** * Checks if this number is greater than or equal to the given one. */ - public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool + final public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) >= 0; } @@ -397,7 +397,7 @@ public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool /** * Checks if this number equals zero. */ - public function isZero() : bool + final public function isZero() : bool { return $this->getSign() === 0; } @@ -405,7 +405,7 @@ public function isZero() : bool /** * Checks if this number is strictly negative. */ - public function isNegative() : bool + final public function isNegative() : bool { return $this->getSign() < 0; } @@ -413,7 +413,7 @@ public function isNegative() : bool /** * Checks if this number is negative or zero. */ - public function isNegativeOrZero() : bool + final public function isNegativeOrZero() : bool { return $this->getSign() <= 0; } @@ -421,7 +421,7 @@ public function isNegativeOrZero() : bool /** * Checks if this number is strictly positive. */ - public function isPositive() : bool + final public function isPositive() : bool { return $this->getSign() > 0; } @@ -429,7 +429,7 @@ public function isPositive() : bool /** * Checks if this number is positive or zero. */ - public function isPositiveOrZero() : bool + final public function isPositiveOrZero() : bool { return $this->getSign() >= 0; } @@ -513,7 +513,7 @@ abstract public function toFloat() : float; */ abstract public function __toString() : string; - public function jsonSerialize() : string + final public function jsonSerialize() : string { return $this->__toString(); } From d374c89deb930a4822b0ad2ad8af0f8963ab270e Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Mon, 30 Oct 2023 23:45:51 +0100 Subject: [PATCH 15/16] Update Psalm to 5.16.0 --- composer.json | 2 +- src/BigDecimal.php | 2 ++ src/BigInteger.php | 2 ++ src/BigRational.php | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3835536..bd67343 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "require-dev": { "phpunit/phpunit": "^10.1", "php-coveralls/php-coveralls": "^2.2", - "vimeo/psalm": "5.15.0" + "vimeo/psalm": "5.16.0" }, "autoload": { "psr-4": { diff --git a/src/BigDecimal.php b/src/BigDecimal.php index 021ba7f..31d22ab 100644 --- a/src/BigDecimal.php +++ b/src/BigDecimal.php @@ -380,6 +380,8 @@ public function remainder(BigNumber|int|float|string $that) : BigDecimal * * @return BigDecimal[] An array containing the quotient and the remainder. * + * @psalm-return array{BigDecimal, BigDecimal} + * * @throws MathException If the divisor is not a valid decimal number, or is zero. */ public function quotientAndRemainder(BigNumber|int|float|string $that) : array diff --git a/src/BigInteger.php b/src/BigInteger.php index fd23420..73dcc89 100644 --- a/src/BigInteger.php +++ b/src/BigInteger.php @@ -531,6 +531,8 @@ public function remainder(BigNumber|int|float|string $that) : BigInteger * * @return BigInteger[] An array containing the quotient and the remainder. * + * @psalm-return array{BigInteger, BigInteger} + * * @throws DivisionByZeroException If the divisor is zero. */ public function quotientAndRemainder(BigNumber|int|float|string $that) : array diff --git a/src/BigRational.php b/src/BigRational.php index 9e07215..fc3060e 100644 --- a/src/BigRational.php +++ b/src/BigRational.php @@ -177,6 +177,8 @@ public function remainder() : BigInteger * Returns the quotient and remainder of the division of the numerator by the denominator. * * @return BigInteger[] + * + * @psalm-return array{BigInteger, BigInteger} */ public function quotientAndRemainder() : array { From 21e0a1e6bc7aa5b640ce8d82b2ff5f251c41a952 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Sun, 26 Nov 2023 15:36:23 +0100 Subject: [PATCH 16/16] Prepare for release --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31e80ab..d468c2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## UNRELEASED (0.12.0) +## [0.12.0](https://github.com/brick/math/releases/tag/0.12.0) - 2023-11-26 💥 **Breaking changes**