Forked from opsec-ee/Erdős-Selfridge-Prime_engine.c
Created
December 25, 2025 23:24
-
-
Save DoddiC/f42d24aa78ffb96c104bf2f2f96471b9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Erdős-Selfridge Prime Categorization Engine - C11 Compatible | |
| * Copyright (c) 2025 H.O <opsec.ee@pm.me> | |
| * Target: 10+ million primes/second | |
| * COMPLEXITY: O(n log m) - Near-linear performance | |
| * Where: n = num primes, m = largest prime val | |
| * | |
| * Optimizations: | |
| * - Enhanced wheel factorization with branch elimination | |
| * - Optimized memory layout for cache performance | |
| * - Fast integer square root without floating point | |
| * - Streamlined hash table with linear probing | |
| * - Bit manipulation optimizations | |
| * gcc -std=c11 -O3 -march=native -flto -Wall -Wextra -DNDEBUG -ffast-math -funroll-loops prime_ee.c -o prime_engine -lm | |
| * ./prime_engine | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdint.h> | |
| #include <stdbool.h> | |
| #include <string.h> | |
| #include <time.h> | |
| // Configuration | |
| #define MAX_PRIMES 1000000 | |
| #define MAX_CATEGORIES 20 | |
| #define FACTORIZATION_BUFFER_SIZE 32 | |
| #define HASH_TABLE_SIZE (MAX_PRIMES * 2) | |
| #define TRACK_FIRST_N_PRIMES 200 | |
| #define MAX_PRIMES_PER_CATEGORY 100 | |
| static const uint8_t wheel_210_increments[48] = { | |
| 4, 6, 10, 12, 16, 18, 22, 24, 30, 32, 36, 38, 42, 44, 48, 50, | |
| 54, 56, 62, 64, 66, 68, 72, 74, 80, 82, 84, 86, 90, 92, 96, 98, | |
| 102, 104, 108, 110, 114, 116, 120, 122, 126, 128, 132, 134, 138, 140, 144, 146 | |
| }; | |
| // Memory-optimized data structures | |
| static uint64_t g_primes[MAX_PRIMES]; | |
| static uint32_t g_prime_count; | |
| // 4-bit packed categories (4x memory reduction) | |
| static uint64_t g_packed_categories[MAX_PRIMES / 16 + 1]; | |
| // Optimized hash table for O(1) prime lookups | |
| static uint32_t g_hash_table[HASH_TABLE_SIZE]; | |
| static const uint32_t HASH_MULTIPLIER = 2654435761U; | |
| // Statistics tracking | |
| typedef struct { | |
| uint32_t count; | |
| uint64_t smallest; | |
| uint64_t largest; | |
| } category_stats_t; | |
| static category_stats_t g_stats[MAX_CATEGORIES]; | |
| // Prime tracking for first 200 primes | |
| typedef struct { | |
| uint64_t primes[MAX_PRIMES_PER_CATEGORY]; | |
| uint32_t count; | |
| } category_prime_list_t; | |
| static category_prime_list_t g_category_primes[MAX_CATEGORIES]; | |
| // Factorization structures | |
| typedef struct { | |
| uint64_t factor; | |
| uint8_t power; | |
| } prime_factor_t; | |
| typedef struct { | |
| prime_factor_t factors[FACTORIZATION_BUFFER_SIZE]; | |
| uint8_t count; | |
| } factorization_t; | |
| // Fast integer square root using bit manipulation | |
| static inline uint64_t fast_isqrt(uint64_t n) { | |
| if (n < 2) return n; | |
| // Find the highest bit set | |
| uint64_t bit = 1ULL; | |
| while (bit <= n >> 2) bit <<= 2; | |
| uint64_t result = 0; | |
| while (bit != 0) { | |
| uint64_t candidate = result + bit; | |
| if (n >= candidate) { | |
| n -= candidate; | |
| result = (result >> 1) + bit; | |
| } else { | |
| result >>= 1; | |
| } | |
| bit >>= 2; | |
| } | |
| return result; | |
| } | |
| // Inline category storage operations | |
| static inline void set_category_packed(uint32_t index, uint8_t category) { | |
| uint32_t word_idx = index / 16; | |
| uint32_t bit_pos = (index % 16) * 4; | |
| uint64_t mask = ~(0xFULL << bit_pos); | |
| g_packed_categories[word_idx] = (g_packed_categories[word_idx] & mask) | | |
| ((uint64_t)category << bit_pos); | |
| } | |
| static inline uint8_t get_category_packed(uint32_t index) { | |
| uint32_t word_idx = index / 16; | |
| uint32_t bit_pos = (index % 16) * 4; | |
| return (g_packed_categories[word_idx] >> bit_pos) & 0xF; | |
| } | |
| // Optimized prime generation with enhanced sieve | |
| static bool generate_primes_optimized(void) { | |
| const uint32_t limit = 16000000; | |
| // Bit-packed sieve | |
| uint8_t* sieve = calloc((limit + 7) / 8, 1); | |
| if (!sieve) return false; | |
| // Mark all odd numbers as potential primes | |
| for (uint32_t i = 3; i <= limit; i += 2) { | |
| sieve[i / 8] |= (1 << (i % 8)); | |
| } | |
| // Sieve of Eratosthenes with wheel optimization | |
| for (uint32_t p = 3; p * p <= limit; p += 2) { | |
| if (sieve[p / 8] & (1 << (p % 8))) { | |
| // Mark multiples using wheel pattern for efficiency | |
| for (uint32_t multiple = p * p; multiple <= limit; multiple += 2 * p) { | |
| sieve[multiple / 8] &= ~(1 << (multiple % 8)); | |
| } | |
| } | |
| } | |
| // Extract primes | |
| g_prime_count = 0; | |
| g_primes[g_prime_count++] = 2; // Add 2 manually | |
| for (uint32_t i = 3; i <= limit && g_prime_count < MAX_PRIMES; i += 2) { | |
| if (sieve[i / 8] & (1 << (i % 8))) { | |
| g_primes[g_prime_count++] = i; | |
| } | |
| } | |
| free(sieve); | |
| return g_prime_count == MAX_PRIMES; | |
| } | |
| // Build optimized hash table for O(1) prime index lookup | |
| static void build_hash_table(void) { | |
| memset(g_hash_table, 0xFF, sizeof(g_hash_table)); | |
| for (uint32_t i = 0; i < g_prime_count; i++) { | |
| uint64_t prime = g_primes[i]; | |
| uint32_t hash = (prime * HASH_MULTIPLIER) % HASH_TABLE_SIZE; | |
| // Linear probing | |
| while (g_hash_table[hash] != UINT32_MAX) { | |
| hash = (hash + 1) % HASH_TABLE_SIZE; | |
| } | |
| g_hash_table[hash] = i; | |
| } | |
| } | |
| // Fast prime index lookup with optimized hash resolution | |
| static int32_t find_prime_index_fast(uint64_t prime) { | |
| uint32_t hash = (prime * HASH_MULTIPLIER) % HASH_TABLE_SIZE; | |
| uint32_t attempts = 0; | |
| while (g_hash_table[hash] != UINT32_MAX && attempts < 100) { | |
| uint32_t index = g_hash_table[hash]; | |
| if (index < g_prime_count && g_primes[index] == prime) { | |
| return (int32_t)index; | |
| } | |
| hash = (hash + 1) % HASH_TABLE_SIZE; | |
| attempts++; | |
| } | |
| return -1; // Not found | |
| } | |
| // Enhanced wheel factorization with branch optimization | |
| static void factorize_wheel_enhanced(uint64_t n, factorization_t* result) { | |
| result->count = 0; | |
| if (n <= 1) return; | |
| // Handle base wheel primes efficiently | |
| static const uint64_t base_primes[] = {2, 3, 5, 7}; | |
| for (int i = 0; i < 4; i++) { | |
| uint64_t p = base_primes[i]; | |
| if (n % p == 0) { | |
| result->factors[result->count].factor = p; | |
| result->factors[result->count].power = 0; | |
| while (n % p == 0) { | |
| n /= p; | |
| result->factors[result->count].power++; | |
| } | |
| result->count++; | |
| } | |
| } | |
| // Use 210-wheel for remaining factors | |
| uint64_t candidate = 11; // First candidate after base primes | |
| uint64_t limit = fast_isqrt(n); | |
| uint32_t wheel_index = 0; | |
| while (candidate <= limit && result->count < FACTORIZATION_BUFFER_SIZE - 1) { | |
| if (n % candidate == 0) { | |
| result->factors[result->count].factor = candidate; | |
| result->factors[result->count].power = 0; | |
| while (n % candidate == 0) { | |
| n /= candidate; | |
| result->factors[result->count].power++; | |
| } | |
| result->count++; | |
| limit = fast_isqrt(n); | |
| } | |
| candidate += wheel_210_increments[wheel_index]; | |
| wheel_index = (wheel_index + 1) % 48; | |
| } | |
| // Handle remaining prime factor | |
| if (n > 1 && result->count < FACTORIZATION_BUFFER_SIZE) { | |
| result->factors[result->count].factor = n; | |
| result->factors[result->count].power = 1; | |
| result->count++; | |
| } | |
| } | |
| // Optimized category computation with memoization | |
| static uint8_t compute_category_optimized(uint32_t prime_index) { | |
| // Check memoized result first | |
| uint8_t cached = get_category_packed(prime_index); | |
| if (cached != 0) return cached; | |
| uint64_t p = g_primes[prime_index]; | |
| uint64_t p_plus_1 = p + 1; | |
| // Factor p+1 | |
| factorization_t factors; | |
| factorize_wheel_enhanced(p_plus_1, &factors); | |
| uint8_t max_category = 0; | |
| bool only_base_factors = true; | |
| // Process each unique prime factor | |
| for (uint8_t i = 0; i < factors.count; i++) { | |
| uint64_t factor = factors.factors[i].factor; | |
| // Base cases | |
| if (factor == 2 || factor == 3) { | |
| if (max_category < 1) max_category = 1; | |
| continue; | |
| } | |
| only_base_factors = false; | |
| // Find factor index using fast hash lookup | |
| int32_t factor_index = find_prime_index_fast(factor); | |
| if (factor_index < 0) { | |
| // Factor not in prime list, skip or handle error | |
| continue; | |
| } | |
| // Recursive category calculation | |
| uint8_t factor_category = compute_category_optimized(factor_index); | |
| if (factor_category > max_category) { | |
| max_category = factor_category; | |
| } | |
| } | |
| uint8_t result = only_base_factors ? 1 : (max_category + 1); | |
| // Memoize result | |
| set_category_packed(prime_index, result); | |
| return result; | |
| } | |
| // High-performance processing with silent computation | |
| static bool process_million_primes_fast(void) { | |
| clock_t start_time = clock(); | |
| // Initialize statistics and prime tracking | |
| memset(g_stats, 0, sizeof(g_stats)); | |
| memset(g_packed_categories, 0, sizeof(g_packed_categories)); | |
| memset(g_category_primes, 0, sizeof(g_category_primes)); | |
| printf("Processing 1,000,000 primes for categorization...\n"); | |
| // SILENT COMPUTATION LOOP | |
| for (uint32_t i = 0; i < g_prime_count; i++) { | |
| uint64_t prime = g_primes[i]; | |
| uint8_t category = compute_category_optimized(i); | |
| if (category < MAX_CATEGORIES) { | |
| g_stats[category].count++; | |
| if (g_stats[category].count == 1) { | |
| g_stats[category].smallest = prime; | |
| g_stats[category].largest = prime; | |
| } else { | |
| if (prime > g_stats[category].largest) { | |
| g_stats[category].largest = prime; | |
| } | |
| } | |
| // Track individual primes for first 200 | |
| if (i < TRACK_FIRST_N_PRIMES && | |
| g_category_primes[category].count < MAX_PRIMES_PER_CATEGORY) { | |
| g_category_primes[category].primes[g_category_primes[category].count] = prime; | |
| g_category_primes[category].count++; | |
| } | |
| } | |
| } | |
| clock_t end_time = clock(); | |
| double total_time = ((double)(end_time - start_time)) / CLOCKS_PER_SEC; | |
| // BATCH OUTPUT | |
| printf("Completed in %.4f seconds\n\n", total_time); | |
| // Print individual primes for first 200 | |
| printf("First %d primes by category:\n", TRACK_FIRST_N_PRIMES); | |
| for (uint8_t cat = 1; cat < MAX_CATEGORIES; cat++) { | |
| if (g_category_primes[cat].count > 0) { | |
| printf("Category %u:\n", cat); | |
| for (uint32_t i = 0; i < g_category_primes[cat].count; i++) { | |
| printf("%4lu", g_category_primes[cat].primes[i]); | |
| if ((i + 1) % 15 == 0) printf("\n"); | |
| else if (i < g_category_primes[cat].count - 1) printf(" "); | |
| } | |
| printf("\n\n"); | |
| } | |
| } | |
| printf("Erdős-Selfridge categorization results:\n"); | |
| for (uint8_t cat = 1; cat < MAX_CATEGORIES; cat++) { | |
| if (g_stats[cat].count > 0) { | |
| printf("Category %2u: first = %7lu last = %8lu count = %u\n", | |
| cat, g_stats[cat].smallest, g_stats[cat].largest, g_stats[cat].count); | |
| } | |
| } | |
| printf("\nPerformance metrics:\n"); | |
| printf(" Total time: %.4f seconds\n", total_time); | |
| printf(" Performance: %.0f primes/second\n", g_prime_count / total_time); | |
| return true; | |
| } | |
| int main(void) { | |
| printf("Erdős-Selfridge Prime Categorization Engine v2.1\n"); | |
| printf("High Performance C11 Compatible Edition\n"); | |
| printf("==============================================\n\n"); | |
| // Generate primes | |
| printf("Generating %u primes...\n", MAX_PRIMES); | |
| if (!generate_primes_optimized()) { | |
| printf("Failed to generate primes\n"); | |
| return 1; | |
| } | |
| printf("Generated %u primes\n\n", g_prime_count); | |
| // Build hash table | |
| build_hash_table(); | |
| // Process all primes | |
| if (!process_million_primes_fast()) { | |
| printf("Processing failed\n"); | |
| return 1; | |
| } | |
| printf("\n"); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment