mpz_t nk, A; mpz_inits(nk, A, NULL);
mpz_mul_ui(nk, n, k);
unsigned long d0 = mpz_fdiv_ui(nk, 10);
mpz_fdiv_q_ui(A, nk, 10);
unsigned long A_ul = mpz_get_ui(A);
mpz_clears(nk, A, NULL);
long double approx = sqrt((long double)A_ul * 10.0L);
long long i_est = (long long)floor((approx - d0) / 10.0L);
unsigned long i_max = (unsigned long)(sqrt((long
double)A_ul) / 10.0L) + 2;
unsigned long max_blocks = (unsigned
long)(log((double)A_ul) * 2.0);
TaskI taskI(d0, A_ul, i_est, i_max);
vector<thread> poolI; poolI.reserve(THREADS);
for (int ti = 0; ti < THREADS; ++ti) {
poolI.emplace_back([&]() {
while (!found.load(memory_order_relaxed)) {
long long b = taskI.block.fetch_add(1,
memory_order_relaxed);
if ((unsigned long)b > max_blocks) return;
long long m = (b + 1) / 2;
long long dir = (b % 2 == 0 ? 1 : -1);
long long i0 = taskI.i_est + dir * m *
BLOCK_I;
if (i0 < 0 || i0 > (long long)taskI.i_max)
continue;
unsigned long start_i = (unsigned long)i0;
unsigned long end_i = start_i + BLOCK_I - 1;
if (end_i > taskI.i_max) end_i = taskI.i_max;
for (unsigned long i = start_i; i <= end_i &&
!found.load(); ++i) {
unsigned long d = taskI.d0 + 10 * i;
if (d <= 1) continue;
if (!mpz_divisible_ui_p(n, d)) continue;
found_d.store(d, memory_order_relaxed);
found.store(true, memory_order_relaxed);
return;
}
}
});
}
for (auto &th : poolI) th.join();
if (found.load()) break;
double Ad = (double)A_ul;
unsigned long q_max = (unsigned long)(2.0 * sqrt(Ad));
TaskQ taskQ(d0, A_ul, q_max);
vector<thread> poolQ; poolQ.reserve(THREADS);
for (int ti = 0; ti < THREADS; ++ti) {
poolQ.emplace_back([&]() {
while (!found.load(memory_order_relaxed)) {
unsigned long b =
taskQ.block.fetch_add(BLOCK_Q, memory_order_relaxed);
if (b > taskQ.q_max) return;
unsigned long end_q = b + BLOCK_Q - 1;
if (end_q > taskQ.q_max) end_q = taskQ.q_max;