#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include <time.h>
#include <string.h>

// BigInt nativo de 128 bits
typedef unsigned __int128 bigint_t;

// Tamaño del bloque: 256 KB
#define SEGMENT_SIZE_BYTES 262144
#define SEGMENT_BITS (SEGMENT_SIZE_BYTES * 8)

#define IS_COMPOSITE(arr, i)  ((arr)[(i) >> 3] &   (1U << ((i) & 7)))
#define SET_COMPOSITE(arr, i) ((arr)[(i) >> 3] |=  (1U << ((i) & 7)))

// Convertir BigInt a String decimal
void bigint_to_string(bigint_t n, char *buffer) {
    if (n == 0) { 
        buffer[0] = '0'; 
        buffer[1] = '\0'; 
        return; 
    }
    char temp[50];
    int i = 0;
    while (n > 0) {
        temp[i++] = '0' + (char)(n % 10);
        n /= 10;
    }
    int j = 0;
    while (i > 0) {
        buffer[j++] = temp[--i];
    }
    buffer[j] = '\0';
}

// Convertir BigInt a Base64 posicional (Radix-64)
void bigint_to_base64(bigint_t n, char *buffer) {
    static const char B64_ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    if (n == 0) {
        buffer[0] = 'A';
        buffer[1] = '\0';
        return;
    }
    char temp[50];
    int i = 0;
    while (n > 0) {
        temp[i++] = B64_ALPHABET[(int)(n % 64)];
        n /= 64;
    }
    int j = 0;
    while (i > 0) {
        buffer[j++] = temp[--i];
    }
    buffer[j] = '\0';
}

// Imprimir BigInt en decimal
void print_bigint(bigint_t n) {
    char buffer[50];
    bigint_to_string(n, buffer);
    printf("%s", buffer);
}

// Convertir BigInt a double
double bigint_to_double(bigint_t temp) {
    double n = 0.0;
    double multiplier = 1.0;
    while(temp > 0) {
        n += (double)(temp % 10) * multiplier;
        temp /= 10;
        multiplier *= 10.0;
    }
    return n;
}

// Leer BigInt desde cadena
bigint_t parse_bigint(const char *str) {
    bigint_t result = 0;
    while (*str) {
        if (*str >= '0' && *str <= '9') {
            result = result * 10 + (*str - '0');
        }
        str++;
    }
    return result;
}

// Exponenciación modular segura para 128 bits: (base^exp) % mod
bigint_t mod_pow(bigint_t base, bigint_t exp, bigint_t mod) {
    bigint_t res = 1;
    base %= mod;
    while (exp > 0) {
        if (exp % 2 == 1) res = (res * base) % mod;
        base = (base * base) % mod;
        exp /= 2;
    }
    return res;
}

// Test de primalidad Miller-Rabin optimizado para 128 bits
bool miller_rabin(bigint_t n, int k) {
    if (n < 2) return false;
    if (n == 2 || n == 3) return true;
    if (n % 2 == 0) return false;

    bigint_t d = n - 1;
    int s = 0;
    while (d % 2 == 0) {
        d /= 2;
        s++;
    }

    static const uint64_t bases[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
    for (int i = 0; i < 12; i++) {
        bigint_t a = bases[i];
        if (n <= a) break;
        bigint_t x = mod_pow(a, d, n);
        if (x == 1 || x == n - 1) continue;
        int composite = 1;
        for (int r = 1; r < s; r++) {
            x = (x * x) % n;
            if (x == n - 1) {
                composite = 0;
                break;
            }
        }
        if (composite) return false;
    }
    return true;
}

// Encuentra el primer número primo mayor o igual a n
bigint_t next_prime(bigint_t n) {
    if (n <= 2) return 2;
    if (n % 2 == 0) n++;
    while (!miller_rabin(n, 5)) {
        n += 2;
    }
    return n;
}

int main(int argc, char *argv[]) {
    bigint_t target = parse_bigint("8300770764");
    if (argc >= 2) target = parse_bigint(argv[1]);

    printf("Buscando el primo numero : ");
    print_bigint(target);
    printf("\n");

    // ---------------------------------------------------------
    // FASE 1: Cálculo del techo matemático
    // ---------------------------------------------------------
    double n_double = bigint_to_double(target);
    double max_val_est = 20.0;
    
    if (n_double >= 6.0) {
        max_val_est = n_double * (log(n_double) + log(log(n_double)) + 1.0); 
    }
    
    bigint_t limit_sqrt = (bigint_t)sqrt(max_val_est) + 100000;

    // ---------------------------------------------------------
    // FASE 2: Generar Primos Base
    // ---------------------------------------------------------
    size_t base_mem_size = (size_t)(limit_sqrt / 8) + 1;
    unsigned char *base_sieve = (unsigned char *)calloc(base_mem_size, 1);
    
    if(!base_sieve) {
        printf("Error: No se pudo asignar memoria base.\n");
        return 1;
    }

    for (bigint_t p = 2; p * p <= limit_sqrt; p++) {
        if (!IS_COMPOSITE(base_sieve, p)) {
            for (bigint_t i = p * p; i <= limit_sqrt; i += p) {
                SET_COMPOSITE(base_sieve, i);
            }
        }
    }

    size_t base_primes_count = 0;
    for (bigint_t p = 2; p <= limit_sqrt; p++) {
        if (!IS_COMPOSITE(base_sieve, p)) base_primes_count++;
    }
    
    bigint_t *primes = (bigint_t *)malloc(base_primes_count * sizeof(bigint_t));
    size_t idx = 0;
    for (bigint_t p = 2; p <= limit_sqrt; p++) {
        if (!IS_COMPOSITE(base_sieve, p)) primes[idx++] = p;
    }
    free(base_sieve);

    // ---------------------------------------------------------
    // FASE 3: LA CRIBA SEGMENTADA
    // ---------------------------------------------------------
    printf("\nIniciando busqueda profunda...\n");
    unsigned char *segment = (unsigned char *)malloc(SEGMENT_SIZE_BYTES);
    
    bigint_t count = 0;
    bigint_t low = 2;
    bigint_t nth_prime = 0;
    bigint_t latest_prime_found = 0; 
    
    clock_t start_cpu_time = clock();
    time_t wall_start_time = time(NULL);
    
    clock_t last_print_time = start_cpu_time;
    double target_double = bigint_to_double(target);

    while (count < target) {
        for(size_t i = 0; i < SEGMENT_SIZE_BYTES; i++) segment[i] = 0;
        
        bigint_t high = low + SEGMENT_BITS - 1;

        if (high > limit_sqrt * limit_sqrt) {
            printf("\n[Error Matematico] Se requiere ampliar la estimacion base.\n");
            break;
        }

        for (size_t i = 0; i < base_primes_count; i++) {
            bigint_t p = primes[i];
            if (p * p > high) break;

            bigint_t first_multiple = (low / p) * p;
            if (first_multiple < low) first_multiple += p;
            if (first_multiple == p)  first_multiple += p;

            for (bigint_t j = first_multiple; j <= high; j += p) {
                SET_COMPOSITE(segment, (size_t)(j - low));
            }
        }

        for (size_t i = 0; i < SEGMENT_BITS; i++) {
            if (!IS_COMPOSITE(segment, i)) {
                count++;
                latest_prime_found = low + i; 
                if (count == target) {
                    nth_prime = latest_prime_found;
                    break;
                }
            }
        }
        
        // ---------------------------------------------------------
        // ACTUALIZACIÓN DE PROGRESO (\r)
        // ---------------------------------------------------------
        clock_t current_cpu_time = clock();
        if ((double)(current_cpu_time - last_print_time) / CLOCKS_PER_SEC >= 0.25) {
            double current_double = bigint_to_double(count);
            double percentage = (current_double / target_double) * 100.0;
            
            // --- CÁLCULO DE LA PROPORCIÓN (RATIO) ---
            char ratio_buf[20] = "  1 / 1.0000";
            if (percentage > 0 && percentage < 100.0) {
                if (percentage < 50.0) {
                    double val = 100.0 / percentage;
                    snprintf(ratio_buf, sizeof(ratio_buf), "  1 / %6.4f", val);
                } else {
                    double val = percentage / (100.0 - percentage);
                    snprintf(ratio_buf, sizeof(ratio_buf), "%6.4f / 1  ", val);
                }
            }

            // --- CÁLCULO DEL PRIMO ESTIMADO REAL Y BASE64 ---
            bigint_t estimated_prime = latest_prime_found;
            time_t now_wall_time = time(NULL);
            double elapsed_wall_sec = difftime(now_wall_time, wall_start_time);
            
            if (current_double > 1000.0) {
                double pnt_target = target_double * log(target_double);
                double pnt_current = current_double * log(current_double);
                double est_val = bigint_to_double(latest_prime_found) * (pnt_target / pnt_current);
                estimated_prime = next_prime((bigint_t)est_val);
            }

            // Conversión del número a String y Base64 posicional
            char est_str[50];
            char est_b64[50];
            bigint_to_string(estimated_prime, est_str);
            bigint_to_base64(estimated_prime, est_b64);

            // --- CÁLCULO ETA ---
            char eta_buf[30] = "Calculando...";
            if (elapsed_wall_sec >= 2.0 && current_double > 0) {
                double rate = current_double / elapsed_wall_sec;
                double remaining_sec = (target_double - current_double) / rate;
                
                time_t eta_time = now_wall_time + (time_t)remaining_sec;
                struct tm *eta_tm = localtime(&eta_time);
                if (eta_tm != NULL) {
                    strftime(eta_buf, sizeof(eta_buf), "%Y-%m-%d %H:%M:%S", eta_tm);
                }
            }

            // Impresión con el formato deseado
            printf("\r[%6.2f%% | %s] P: ", percentage, ratio_buf);
            print_bigint(latest_prime_found);
            printf(" | Est: %s %s | ETA: %s   ", est_str, est_b64, eta_buf);
            fflush(stdout);
            
            last_print_time = current_cpu_time;
        }

        if (nth_prime > 0) break;
        low += SEGMENT_BITS;
    }

    // Limpieza final de la línea
    printf("\r                                                                                                                                                                                              \r");
    
    double elapsed_total = (double)(clock() - start_cpu_time) / CLOCKS_PER_SEC;

    // ---------------------------------------------------------
    // RESULTADOS
    // ---------------------------------------------------------
    printf("\n================ RESULTADOS ================\n");
    printf("El primo numero ");
    print_bigint(target);
    printf(" es : ");
    print_bigint(nth_prime);
    printf("\n");
    
    char final_b64[50];
    bigint_to_base64(nth_prime, final_b64);
    
    printf("En formato Base64     : %s\n", final_b64);
    printf("Tiempo de calculo     : %.2f segundos\n", elapsed_total);
    printf("Memoria RAM total     : < 5 MB\n");
    printf("============================================\n");

    free(primes);
    free(segment);
    return 0;
}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: