Skip to content

Commit 5380f1c

Browse files
committed
refactor: Improve Pollard's Rho factorization by using LCG for randomness and optimizing stack management
1 parent 561047f commit 5380f1c

File tree

1 file changed

+26
-14
lines changed

1 file changed

+26
-14
lines changed

weilycoder/number-theory/factorize.hpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* @brief Functions for factorizing numbers using Pollard's Rho algorithm
77
*/
88

9+
#include "../const_rand.hpp"
910
#include "mod_utility.hpp"
1011
#include "prime.hpp"
1112
#include <algorithm>
@@ -27,6 +28,7 @@ namespace weilycoder {
2728
template <bool bit32 = false> constexpr uint64_t pollard_rho(uint64_t x, uint64_t c) {
2829
if (x % 2 == 0)
2930
return 2;
31+
c = c % (x - 1) + 1;
3032
uint32_t step = 0, goal = 1;
3133
uint64_t s = 0, t = 0;
3234
uint64_t value = 1;
@@ -57,11 +59,10 @@ template <bool bit32 = false> constexpr uint64_t pollard_rho(uint64_t x, uint64_
5759
* @return A non-trivial factor of x
5860
*/
5961
template <bool bit32 = false> uint64_t pollard_rho(uint64_t x) {
60-
static std::minstd_rand rng{};
6162
if (x % 2 == 0)
6263
return 2;
63-
uint64_t c = rng() % (x - 1) + 1;
64-
return pollard_rho<bit32>(x, c);
64+
static std::minstd_rand rng{};
65+
return pollard_rho<bit32>(x, rng());
6566
}
6667

6768
/**
@@ -106,30 +107,41 @@ template <bool bit32 = false> std::vector<uint64_t> factorize(uint64_t x) {
106107
*/
107108
template <size_t N = 64, bool bit32 = false>
108109
constexpr std::array<uint64_t, N> factorize_fixed(uint64_t x) {
110+
uint32_t random_state = 1;
109111
size_t factor_idx = 0, stk_idx = 0;
110112
std::array<uint64_t, N> factors{};
111-
std::array<std::pair<uint64_t, size_t>, 64> stk{};
112-
stk[stk_idx++] = {x, 1};
113+
std::array<uint64_t, 64> stk_val{};
114+
std::array<size_t, 64> stk_cnt{};
115+
stk_val[stk_idx] = x, stk_cnt[stk_idx++] = 1;
113116
while (stk_idx > 0) {
114-
auto [cur, cnt] = stk[--stk_idx];
117+
uint64_t cur = stk_val[--stk_idx];
118+
size_t cnt = stk_cnt[stk_idx];
115119
if (cur == 1)
116120
continue;
117-
if (is_prime(cur))
118-
std::fill(factors.begin() + factor_idx, factors.begin() + factor_idx + cnt, cur),
119-
factor_idx += cnt;
120-
else {
121+
if (is_prime(cur)) {
122+
for (size_t i = 0; i < cnt; ++i)
123+
factors[factor_idx++] = cur;
124+
} else {
121125
uint64_t factor = cur;
122126
do
123-
factor = pollard_rho<bit32>(cur);
127+
factor = pollard_rho<bit32>(cur, lcg_nr(random_state));
124128
while (factor == cur);
125129
size_t factor_count = 0;
126130
while (cur % factor == 0)
127131
cur /= factor, ++factor_count;
128-
stk[stk_idx++] = {cur, cnt};
129-
stk[stk_idx++] = {factor, factor_count * cnt};
132+
stk_val[stk_idx] = cur, stk_cnt[stk_idx++] = cnt;
133+
stk_val[stk_idx] = factor, stk_cnt[stk_idx++] = factor_count * cnt;
134+
}
135+
}
136+
for (size_t i = 1; i < factor_idx; ++i) {
137+
uint64_t key = factors[i];
138+
size_t j = i;
139+
while (j > 0 && factors[j - 1] > key) {
140+
factors[j] = factors[j - 1];
141+
--j;
130142
}
143+
factors[j] = key;
131144
}
132-
std::sort(factors.begin(), factors.begin() + factor_idx);
133145
return factors;
134146
}
135147
} // namespace weilycoder

0 commit comments

Comments
 (0)