Hola buenas tardes, voy a compartirles un algoritmo que prepare y me gustaria que lo probaran y me compartieran los tiempos, les comento que en mi maquina uso el exponente de prueba m110503 y con mi maquina logro alcanzar los 10 segundos lo cual me parece muy eficiente ya que al principio tenia algoritmos que lo hacia en 65 segundos, con optimizaciones logre bajar a 16 segundos y alli me habia quedado un tiempo y llegue a pensar que era por mi maquina, pero ven que logre mejorar los tiempos aun mas. , mi equipo es una hp i7 de 11va generacion. La idea de compartir el algoritmo es ver si logran con un buen equipo llegar a tiempos de gimps los cual aunque dificil seria fabuloso. Lo que si agradeceria es que si le hacen mejoras lo compartan para seguir desarrollando. saludos cordiales a todos.
[08:08, 14/8/2026] asofutlag competiciones: #include <iostream>
#include <cstdlib>
#include <gmp.h>
#include <omp.h>
// Estructura alineada a 64 bytes para eliminar el False Sharing entre núcleos de CPU
struct alignas(64) WorkerData {
mpz_t v; // Resultado del cuadrado
mpz_t t_sum; // Suma temporal para términos cruzados
};
void tdll_guanipa_v16_fast(int p) {
int k = p / 3;
mpz_t s, M, s0, s1, s2, s_next, temp_h, temp_l;
mpz_t v01, v02, v12;
mpz_inits(s, M, s0, s1, s2, s_next, temp_h, temp_l, v01, v02, v12, NULL);
// PRE-ASIGNACIÓN DE MEMORIA: Clave para eliminar reallocs lentos en el bucle
mpz_realloc2(s, p + 128);
mpz_realloc2(M, p + 128);
mpz_realloc2(s0, k + 128);
mpz_realloc2(s1, k + 128);
mpz_realloc2(s2, k + 128);
mpz_realloc2(s_next, 2 * p + 128);
mpz_realloc2(temp_h, p + 128);
mpz_realloc2(temp_l, p + 128);
mpz_realloc2(v01, 2 * k + 128);
mpz_realloc2(v02, 2 * k + 128);
mpz_realloc2(v12, 2 * k + 128);
WorkerData workers[6];
for (int i = 0; i < 6; i++) {
mpz_init(workers.v);
mpz_init(workers.t_sum);
mpz_realloc2(workers.v, 2 * k + 128);
mpz_realloc2(workers.t_sum, k + 128);
}
mpz_set_ui(s, 4);
mpz_set_ui(M, 1);
mpz_mul_2exp(M, M, p);
mpz_sub_ui(M, M, 1);
std::cout << "\n⚡ MOTOR GUANIPA V16 FAST-DIRECT | M" << p << " | 6 Hilos Persistentes\n";
double start = omp_get_wtime();
// POOL DE HILOS PERSISTENTE (Se crea una sola vez)
#pragma omp parallel num_threads(6)
{
int tid = omp_get_thread_num();
for (int i = 1; i <= p - 2; i++) {
// Paso 1: División de s en 3 bloques (Hilo Maestro)
#pragma omp single
{
mpz_tdiv_r_2exp(s0, s, k);
mpz_tdiv_q_2exp(s_next, s, k);
mpz_tdiv_r_2exp(s1, s_next, k);
mpz_tdiv_q_2exp(s2, s_next, k);
} // Barrera implícita: garantiza que s0, s1, s2 están listos para todos
// Paso 2: Asignación ESTATICA de los 6 cuadrados (Cero sobrecosto de tareas)
switch (tid) {
case 0:
mpz_mul(workers[0].v, s0, s0); // v0
break;
case 1:
mpz_mul(workers[1].v, s1, s1); // v1
break;
case 2:
mpz_mul(workers[2].v, s2, s2); // v2
break;
case 3:
mpz_add(workers[3].t_sum, s0, s1);
mpz_mul(workers[3].v, workers[3].t_sum, workers[3].t_sum); // v01
break;
case 4:
mpz_add(workers[4].t_sum, s0, s2);
mpz_mul(workers[4].v, workers[4].t_sum, workers[4].t_sum); // v02
break;
case 5:
mpz_add(workers[5].t_sum, s1, s2);
mpz_mul(workers[5].v, workers[5].t_sum, workers[5].t_sum); // v12
break;
}
#pragma omp barrier // Espera ultrarrápida por los 6 cuadrados
// Paso 3: Reconstrucción PARALELA de términos cruzados
switch (tid) {
case 0:
mpz_sub_ui(s_next, workers[0].v, 2);
break;
case 3:
mpz_sub(v01, workers[3].v, workers[0].v);
mpz_sub(v01, v01, workers[1].v);
break;
case 4:
mpz_sub(v02, workers[4].v, workers[0].v);
mpz_sub(v02, v02, workers[2].v);
mpz_add(v02, v02, workers[1].v);
break;
case 5:
mpz_sub(v12, workers[5].v, workers[1].v);
mpz_sub(v12, v12, workers[2].v);
break;
default:
break;
}
#pragma omp barrier
// Paso 4: Ensamblado y Reducción Fast-Mersenne (Hilo Maestro)
#pragma omp single
{
mpz_mul_2exp(temp_l, v01, k);
mpz_add(s_next, s_next, temp_l);
mpz_mul_2exp(temp_l, v02, 2 * k);
mpz_add(s_next, s_next, temp_l);
mpz_mul_2exp(temp_l, v12, 3 * k);
mpz_add(s_next, s_next, temp_l);
mpz_mul_2exp(temp_l, workers[2].v, 4 * k); // v2
mpz_add(s_next, s_next, temp_l);
// Reducción modular rápida modulo (2^p - 1)
mpz_tdiv_r_2exp(temp_l, s_next, p);
mpz_tdiv_q_2exp(temp_h, s_next, p);
mpz_add(s, temp_l, temp_h);
if (mpz_cmp(s, M) >= 0) {
mpz_sub(s, s, M);
}
}
}
}
double end = omp_get_wtime();
if (mpz_cmp(s, M) == 0) mpz_set_ui(s, 0);
std::cout << "🏁 RESULTADO: " << (end - start) << " seg | Popcount: "
<< mpz_popcount(s) << std::endl;
// Limpieza de memoria
for (int i = 0; i < 6; i++) {
mpz_clear(workers.v);
mpz_clear(workers.t_sum);
}
mpz_clears(s, M, s0, s1, s2, s_next, temp_h, temp_l, v01, v02, v12, NULL);
}
int main(int argc, char *argv[]) {
int p = (argc > 1) ? atoi(argv[1]) : 110503;
tdll_guanipa_v16_fast(p);
return 0;
}
algoritmo tdll de 10 segundos.
g++ -O3 -march=native -fopenmp tdll_guanipa_v16_fast.cpp -lgmp -o tdll_v16
para compilar
./tdll_v16 110503