mr4th/src/euler.c

300 lines
6.9 KiB
C

#include "base/base_inc.h"
#include "os/os_inc.h"
#include "base/base_inc.c"
#include "base/base_big_functions.c"
#include "os/os_inc.c"
#include <stdio.h>
////////////////////////////////
// NOTE(allen): Types
typedef struct Array_U8{
U8 *v;
U64 count;
} Array_U8;
typedef struct EulerData{
U8 *v;
U64 count;
U64 line_count;
} EulerData;
typedef struct ListNode_U32{
struct ListNode_U32 *next;
Array_U32 array;
} ListNode_U32;
typedef struct List_U32{
ListNode_U32 *first;
ListNode_U32 *last;
U64 node_count;
U64 total_count;
} List_U32;
typedef struct Pair_U64{
U64 a;
U64 b;
} Pair_U64;
typedef struct Pair_U32{
U32 a;
U32 b;
} Pair_U32;
typedef struct U64x3{
U64 v[3];
} U64x3;
typedef struct U64x3_DivR{
U64x3 q;
U64 r;
} U64x3_DivR;
typedef U64 U64xN;
////////////////////////////////
// NOTE(allen): Assembly Function Declarations
c_linkage U64 triangle_number(U64 n);
c_linkage U64 sum_of_squares(U64 n);
c_linkage void fibonacci_stepper_mul(void *dst, void *src);
c_linkage void fibonacci_stepper_sqr(void *dst);
c_linkage U64 fibonacci_number(U64 n);
c_linkage U64 fibonacci_sigma(U64 n);
c_linkage U64 choose__asm(U64 *buffer, U64 n, U64 m);
c_linkage void fill_factorial_table(U64 *table, U64 count);
c_linkage U32 prime_sieve__asm(B8 *table_memory,
U32 *primes_list,
U32 first, U32 opl,
ListNode_U32 *node);
c_linkage void factorization_table__asm(U32 *table_memory, U32 count);
c_linkage U32 get_prime_factor(U32 *fact_tbl, U32 count, U32 n);
c_linkage Pair_U32 max_divide(U32 n, U32 f);
c_linkage U32 divisor_count(U32 *fact_tbl, U32 count, U32 n);
c_linkage U64 divisor_sum(U32 *fact_tbl, U32 count, U32 n);
c_linkage Pair_U64 find_bounded_factors(U64 min, U64 max, U64 target_product);
c_linkage U64 gcd_euclidean(U64 a, U64 b);
c_linkage U64 lcm_euclidean(U64 a, U64 b);
c_linkage EulerData euler_data_from_text__asm(String8 text, U8 *memory);
c_linkage EulerData euler_data_from_text_2dig__asm(String8 text, U8 *memory);
c_linkage U64x3 add_u64x3(U64x3 a, U64x3 b);
c_linkage U64x3 add_small_u64x3(U64x3 a, U64 b);
c_linkage U64x3 mul_small_u64x3(U64x3 a, U64 b);
c_linkage U64x3_DivR div_small_u64x3(U64x3 n, U64 d);
c_linkage U64x3 u64x3_from_dec(U8 *digits, U64 count);
c_linkage U64 dec_from_u64x3__asm(U8 *out, U64x3 x);
c_linkage void add_small_in_place_u64xn(U64xN *a, U64 b);
c_linkage void mul_small_in_place_u64xn(U64xN *a, U64 b);
c_linkage U64 div_small_in_place_u64xn(U64xN *n, U64 d);
c_linkage U64 dec_from_u64xn__asm(U8 *out, U64xN *x); // x is "destroyed" by this call
////////////////////////////////
// NOTE(allen): Helpers/Wrappers with C/C++ Niceness
function U64
choose(U64 n, U64 m){
U64 result = 0;
if (m <= n){
ArenaTemp scratch = arena_get_scratch(0, 0);
U64 *buffer = push_array(scratch.arena, U64, n + 1);
result = choose__asm(buffer, n, m);
arena_end_temp(&scratch);
}
return(result);
}
function void
prime_sieve(Arena *arena, List_U32 *primes, U32 first, U32 opl){
Assert(Implies(primes->node_count == 0, first == 3));
Assert(first < opl);
// allocate memory
ArenaTemp scratch = arena_get_scratch(&arena, 1);
U32 max_count = opl - first;
U32 *primes_list = push_array(arena, U32, max_count);
B8 *sieve_table = push_array(scratch.arena, B8, max_count);
// run sieve
U32 count = prime_sieve__asm(sieve_table, primes_list, first, opl,
primes->first);
// put back memory we didn't use in the primes list
arena_pop_amount(arena, sizeof(*primes_list)*(max_count - count));
arena_align(arena, 8);
// insert new primes block onto the list
Array_U32 array = {0};
array.vals = primes_list;
array.count = count;
ListNode_U32 *node = push_array(arena, ListNode_U32, 1);
node->array = array;
SLLQueuePush(primes->first, primes->last, node);
primes->node_count += 1;
primes->total_count += array.count;
arena_end_temp(&scratch);
}
function Array_U32
factorization_table(Arena *arena, U32 count){
U32 *tbl = push_array(arena, U32, count);
factorization_table__asm(tbl, count);
Array_U32 result = {0};
result.vals = tbl;
result.count = count;
return(result);
}
function EulerData
euler_data_from_text(Arena *arena, String8 text, U64 num_digits){
Assert(num_digits == 1 || num_digits == 2);
U8 *memory = push_array(arena, U8, text.size);
EulerData result = {0};
if (num_digits == 1){
result = euler_data_from_text__asm(text, memory);
}
else if (num_digits == 2){
result = euler_data_from_text_2dig__asm(text, memory);
}
arena_pop_amount(arena, text.size - result.count);
arena_align(arena, 8);
return(result);
}
function Array_U8
dec_from_u64x3(Arena *arena, U64x3 x){
Array_U8 result = {0};
if (x.v[0] == 0 && x.v[1] == 0 && x.v[2] == 0){
local U8 zbuffer[1] = {0};
result.v = zbuffer;
result.count = 1;
}
else{
U64 cap = 60;
U8 *buffer = push_array(arena, U8, cap);
U64 count = dec_from_u64x3__asm(buffer, x);
arena_pop_amount(arena, cap - count);
arena_align(arena, 8);
result.v = buffer;
result.count = count;
}
return(result);
}
function U64xN*
copy_u64xn(Arena *arena, U64xN *x){
U64 size = (*x) + 1;
U64xN *result = push_array(arena, U64, size);
MemoryCopy(result, x, sizeof(*x)*size);
return(result);
}
function Array_U8
dec_from_u64xn(Arena *arena, U64xN *x){
Array_U8 result = {0};
if (*x == 0){
local U8 zbuffer[1] = {0};
result.v = zbuffer;
result.count = 1;
}
else{
ArenaTemp scratch = arena_get_scratch(&arena, 1);
U64 cap = (*x)*20;
U64xN *x_copy = copy_u64xn(scratch.arena, x);
U8 *buffer = push_array(arena, U8, cap);
U64 count = dec_from_u64xn__asm(buffer, x_copy);
arena_pop_amount(arena, cap - count);
arena_align(arena, 8);
result.v = buffer;
result.count = count;
arena_release_scratch(&scratch);
}
return(result);
}
function U64
dec_repeating_cycle_score(U64 d){
U64 result = 0;
if (d > 0){
// divide out 2s
for (;(d & 1) == 0;){
d >>= 1;
}
// divide out 5s
for (;(d % 5) == 0;){
d /= 5;
}
// check 9s
if (d > 1){
U64 score = 1;
U64 buf1[60] = {1, 9};
U64 buf2[60] = {0};
for (;;){
memcpy(buf2, buf1, sizeof(buf1));
U64 remainder = div_small_in_place_u64xn(buf1, d);
if (remainder == 0){
break;
}
score += 1;
memcpy(buf1, buf2, sizeof(buf1));
mul_small_in_place_u64xn(buf1, 10);
add_small_in_place_u64xn(buf1, 9);
}
result = score;
}
}
return(result);
}
int
main(void){
Arena *arena = arena_alloc();
U64 max_score = 0;
for (U64 d = 1; d < 1000; d += 1){
U64 score = dec_repeating_cycle_score(d);
max_score = Max(score, max_score);
printf("score(%llu) = %llu\n", d, score);
}
return(0);
}
//$ console //