300 lines
6.9 KiB
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 //
|