From f09d56356f9b8bc54ff5becf7098aa8761ed4537 Mon Sep 17 00:00:00 2001 From: Viktor Khokhryakov Date: Fri, 14 Feb 2025 14:43:09 +0400 Subject: [PATCH 1/5] Optimize NativeCalculator::doDiv() --- src/Internal/Calculator/NativeCalculator.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Internal/Calculator/NativeCalculator.php b/src/Internal/Calculator/NativeCalculator.php index 6acd063..7f0b9ac 100644 --- a/src/Internal/Calculator/NativeCalculator.php +++ b/src/Internal/Calculator/NativeCalculator.php @@ -488,6 +488,21 @@ private function doDiv(string $a, string $b) : array $r = $a; // remainder $z = $y; // focus length, always $y or $y+1 + /** @psalm-var numeric-string $b */ + $nb = $b * 1; // cast to number + // performance optimization in cases where the remainder will never cause int overflow + if (is_int(($nb - 1) * 10 + 9)) { + $r = (int) \substr($a, 0, $z); + + for ($i = $z; $i < $x; $i++) { + $n = $r * 10 + (int) $a[$i]; + $q .= (int) ($n / $nb); + $r = $n % $nb; + } + + return [ltrim($q, '0') ?: '0', (string) $r]; + } + for (;;) { $focus = \substr($a, 0, $z); From da22d01a87bd6c87b173a94b94b7842e5023b6e1 Mon Sep 17 00:00:00 2001 From: Viktor Khokhryakov Date: Sat, 15 Feb 2025 09:40:01 +0400 Subject: [PATCH 2/5] Fix the initial remainder in optimized case of NativeCalculator::doDiv() --- src/Internal/Calculator/NativeCalculator.php | 4 ++-- tests/BigIntegerTest.php | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Internal/Calculator/NativeCalculator.php b/src/Internal/Calculator/NativeCalculator.php index 7f0b9ac..369c1b0 100644 --- a/src/Internal/Calculator/NativeCalculator.php +++ b/src/Internal/Calculator/NativeCalculator.php @@ -492,9 +492,9 @@ private function doDiv(string $a, string $b) : array $nb = $b * 1; // cast to number // performance optimization in cases where the remainder will never cause int overflow if (is_int(($nb - 1) * 10 + 9)) { - $r = (int) \substr($a, 0, $z); + $r = (int) \substr($a, 0, $z - 1); - for ($i = $z; $i < $x; $i++) { + for ($i = $z - 1; $i < $x; $i++) { $n = $r * 10 + (int) $a[$i]; $q .= (int) ($n / $nb); $r = $n % $nb; diff --git a/tests/BigIntegerTest.php b/tests/BigIntegerTest.php index 929e2f7..5457ea8 100644 --- a/tests/BigIntegerTest.php +++ b/tests/BigIntegerTest.php @@ -1253,6 +1253,9 @@ public static function providerQuotientAndRemainder() : array ['49283205308081983923480483094304390249024223', '-23981985358744892239240813', '-2055009398548863185', '20719258837232321643854818'], ['-8378278174814983902084304176539029302438924', '384758527893793829309012129991', '-21775419041855', '-367584271343844173835372665619'], ['-444444444444444444444444444444444444411111', '-33333333333333', '13333333333333466666666666667', '-33333333300000'], + + ['922337203685477581000000000', '922337203685477580', '1000000000', '1000000000'], + ['922337203685477581000000000', '922337203685477581', '1000000000', '0'], ]; } From 803decdf29dd17a0ec60f261fe4eebfe557a5655 Mon Sep 17 00:00:00 2001 From: Viktor Khokhryakov Date: Wed, 26 Feb 2025 09:14:51 +0400 Subject: [PATCH 3/5] Prefer intdiv Co-authored-by: Benjamin Morel --- src/Internal/Calculator/NativeCalculator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Internal/Calculator/NativeCalculator.php b/src/Internal/Calculator/NativeCalculator.php index 369c1b0..7cd8217 100644 --- a/src/Internal/Calculator/NativeCalculator.php +++ b/src/Internal/Calculator/NativeCalculator.php @@ -496,7 +496,7 @@ private function doDiv(string $a, string $b) : array for ($i = $z - 1; $i < $x; $i++) { $n = $r * 10 + (int) $a[$i]; - $q .= (int) ($n / $nb); + $q .= intdiv($n, $nb); $r = $n % $nb; } From afc29765c2a08dab26ebe98c302da4454b4b731a Mon Sep 17 00:00:00 2001 From: Viktor Khokhryakov Date: Wed, 26 Feb 2025 09:25:58 +0400 Subject: [PATCH 4/5] Add psalm annotation to clarify the variable type --- src/Internal/Calculator/NativeCalculator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Internal/Calculator/NativeCalculator.php b/src/Internal/Calculator/NativeCalculator.php index 7cd8217..63e10e4 100644 --- a/src/Internal/Calculator/NativeCalculator.php +++ b/src/Internal/Calculator/NativeCalculator.php @@ -496,6 +496,7 @@ private function doDiv(string $a, string $b) : array for ($i = $z - 1; $i < $x; $i++) { $n = $r * 10 + (int) $a[$i]; + /** @psalm-var int $nb */ $q .= intdiv($n, $nb); $r = $n % $nb; } From b0b5873f21c3c593bcccffc94be2bbea097b1aa0 Mon Sep 17 00:00:00 2001 From: Viktor Khokhryakov Date: Wed, 26 Feb 2025 09:49:00 +0400 Subject: [PATCH 5/5] Use fully qualified name for native functions --- src/Internal/Calculator/NativeCalculator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Internal/Calculator/NativeCalculator.php b/src/Internal/Calculator/NativeCalculator.php index 63e10e4..0299f14 100644 --- a/src/Internal/Calculator/NativeCalculator.php +++ b/src/Internal/Calculator/NativeCalculator.php @@ -497,11 +497,11 @@ private function doDiv(string $a, string $b) : array for ($i = $z - 1; $i < $x; $i++) { $n = $r * 10 + (int) $a[$i]; /** @psalm-var int $nb */ - $q .= intdiv($n, $nb); + $q .= \intdiv($n, $nb); $r = $n % $nb; } - return [ltrim($q, '0') ?: '0', (string) $r]; + return [\ltrim($q, '0') ?: '0', (string) $r]; } for (;;) {