aoc-2019-c

git clone https://git.sinitax.com/sinitax/aoc-2019-c
Log | Files | Refs | README | sfeed.txt

commit a56db3ca197612211365480617a15d3c14b5a680
parent 915a11e0c7b0a0fd23a1f6f60d6282442aa25a8c
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat,  5 Jun 2021 20:35:32 +0200

Add own multiple precision integer library

Diffstat:
M.gitignore | 1+
Mlibs/Makefile | 15++++++++++++++-
Alibs/include/aoc.h | 5+++++
Alibs/include/maxint.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlibs/include/util.h | 2+-
Dlibs/include/wrapper.h | 6------
Alibs/src/maxint.c | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlibs/src/util.c | 8++++----
Alibs/tests/maxint.c | 23+++++++++++++++++++++++
Msrc/day1/main.c | 3+--
Msrc/day2/main.c | 5++---
11 files changed, 399 insertions(+), 17 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -2,3 +2,4 @@ compile_commands.json main .cache build +vgcore* diff --git a/libs/Makefile b/libs/Makefile @@ -1,4 +1,4 @@ -CFLAGS = -I include -g +CFLAGS = -I include -g -L build LDLIBS = all: build/libaoc.a @@ -14,3 +14,16 @@ build/%.o: src/%.c include/%.h | build build/libaoc.a: build/util.o build/wrapper.o ar rcs $@ $^ + +build/test_%: tests/%.c + $(CC) -o $@ $< $(CFLAGS) $(LDLIBS) + +build/test_maxint: tests/maxint.c build/maxint.o + $(CC) -o $@ $^ $(CFLAGS) $(LDLIBS) -laoc + +build/test_%.log: build/test_% + @echo "--- Running test: $< ---" + @valgrind --track-origins=yes --leak-check=full $< 2>&1 | tee $@ + +tests: build/test_maxint.log + diff --git a/libs/include/aoc.h b/libs/include/aoc.h @@ -0,0 +1,5 @@ +#include "util.h" +#include "partinfo.h" + +void part1(struct partinfo *p); +void part2(struct partinfo *p); diff --git a/libs/include/maxint.h b/libs/include/maxint.h @@ -0,0 +1,61 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "util.h" + +#define MI_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MI_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MI_SWAP(a,b) do { typeof(a) t = a; a = b; b = t; } while (0) + +#define MI_DIVCEIL(a,b) ((a) / (b) + ((a) % (b) != 0)) + +#define MI_BIT(a,n) ((mi_ul) ((a) >> (n)) & 1) +#define MI_BITA(a,m,n) ((mi_ul) ((a)[(n) / (m)] >> ((n) % (m))) & 1) + +#define MI_ULBYTES (sizeof(mi_ul)) +#define MI_ULBITS (8 * sizeof(mi_ul)) + +#define MI_NEG 1 +#define MI_POS 0 + +/* unsigned underlying type */ +typedef uint64_t mi_ul; + +struct maxint { + mi_ul* data; + mi_ul imm; + size_t size, last; + uint8_t sign; +}; + +void mi_shrink(struct maxint *m1); + +int mi_cmp(const struct maxint *m1, const struct maxint *m2); // m1 < m2 ? m2 > m1 ? 1 : 0 : -1 + +void mi_add(struct maxint *m1, const struct maxint *m2); // m1 += m2 +void mi_sub(struct maxint *m1, const struct maxint *m2); // m1 -= m2 +void mi_shl(struct maxint *m1, int64_t shift); +void mi_mul(struct maxint *m1, const struct maxint *m2); // m1 *= m2 +void mi_div(struct maxint *m1, struct maxint *m2, const struct maxint *m3); // m1 /= m3, m2 %= m3 +void mi_set(struct maxint *m1, const struct maxint *m2); // m1 = m2 +void mi_setv(struct maxint *m1, mi_ul v, int sign); +void mi_swap(struct maxint *m1, struct maxint *m2); // m1 <=> m2 + +void mi_resize(struct maxint *m1, size_t size); + +const struct maxint* mi_imm(struct maxint *dst, mi_ul v, int sign); + +mi_ul mi_cast_ul(const struct maxint *m1); + +void mi_parse(struct maxint *m1, const char *vstr); + +void mi_free(struct maxint *m1); + +int mi_zero(const struct maxint *m1); + +char* mi_convstr(const struct maxint *m1, int base, const char *alph); +char* mi_hexstr(const struct maxint *m1, int cap); +char* mi_decstr(const struct maxint *m1); + +extern struct maxint mi_tmp; diff --git a/libs/include/util.h b/libs/include/util.h @@ -26,7 +26,7 @@ const char* ntoken(const char *start, const char *end, size_t *len, const char * int min(int a, int b); int max(int a, int b); -void* assertp(void *alloc); +void* chkp(void *alloc); void* memdup(void *data, size_t size); int readall(int fd, void **data, size_t *read); diff --git a/libs/include/wrapper.h b/libs/include/wrapper.h @@ -1,6 +0,0 @@ -#include "util.h" -#include "partinfo.h" - -void part1(struct partinfo *p); -void part2(struct partinfo *p); - diff --git a/libs/src/maxint.c b/libs/src/maxint.c @@ -0,0 +1,287 @@ +#include "maxint.h" + +struct maxint mi_tmp; + +void +mi_add_internal(struct maxint *m1, const struct maxint *m2, int m2_sign) +{ + int carry, swapped; + size_t i; + mi_ul v; + + if (m2->size >= m1->size) + mi_resize(m1, m2->size + 1); + + if (m1->sign != m2_sign) { + for (carry = i = 0; i < m1->size; i++) { + v = (i < m2->size ? m2->data[i] : 0); + m1->data[i] -= v + carry; + carry = m1->data[i] + v + carry < m1->data[i]; + } + + if (carry == 1) { + if (m1->data[0] > 0) { + m1->data[0]--; + for (i = 0; i < m1->size; i++) + m1->data[i] = ~m1->data[i]; + } else { + for (i = 0; i < m1->size; i++) + m1->data[i] = ~m1->data[i]; + m1->data[0]++; + } + m1->sign ^= 1; + } + } else { + for (carry = i = 0; i < m1->size; i++) { + v = (i < m2->size ? m2->data[i] : 0); + m1->data[i] += v + carry; + carry = m1->data[i] - v - carry > m1->data[i]; + } + } +} + +void +mi_add(struct maxint *m1, const struct maxint *m2) +{ + mi_add_internal(m1, m2, m2->sign); +} + +void +mi_sub(struct maxint *m1, const struct maxint *m2) +{ + mi_add_internal(m1, m2, m2->sign ^ 1); +} + +int +mi_cmp(const struct maxint *m1, const struct maxint *m2) +{ + size_t i; + mi_ul v1, v2; + + for (i = 0; i < MI_MAX(m1->size, m2->size); i++) { + v1 = (i >= m1->size ? 0 : m1->data[i]); + v2 = (i >= m2->size ? 0 : m2->data[i]); + if (v1 != v2) return v1 > v2 ? 1 : -1; + } + + return 0; +} + +int +mi_lastset(struct maxint *m1) +{ + int64_t i; + + for (i = m1->size - 1; i >= 0; i--) + if (m1->data[i] != 0) return i; + return 0; +} + +void +mi_shl(struct maxint *m1, int64_t shift) +{ + size_t newsize; + int64_t i, k; + + if (shift > 0) + mi_resize(m1, mi_lastset(m1) + MI_DIVCEIL(shift, MI_ULBITS)); + + for (i = 0; i < m1->size * MI_ULBITS; i++) { + k = (shift >= 0) ? (m1->size * MI_ULBITS - 1 - i) : i; + m1->data[k / MI_ULBITS] &= ~((mi_ul) 1 << (k % MI_ULBITS)); + if (k - shift >= 0 && k - shift < MI_ULBITS) + m1->data[k / MI_ULBITS] |= MI_BITA(m1->data, MI_ULBITS, k - shift) + << (k % MI_ULBITS); + //printf("%li ", k); + //for (int j = 0; j < MI_ULBITS; j++) { + // if (j == k % MI_ULBITS) + // printf("X"); + // else + // printf("%c", MI_BITA(m1->data, MI_ULBITS, j) ? '1' : '0'); + //} + //printf("\n"); + } +} + +void +mi_mul(struct maxint *m1, const struct maxint *m2) +{ + struct maxint sum = { 0 }, tmp = { 0 }; + int64_t i; + + mi_setv(&sum, 0, MI_POS); + for (i = m1->size * MI_ULBITS - 1; i >= 0; i--) { + if (MI_BITA(m1->data, MI_ULBITS, i)) + mi_add(&sum, m2); + mi_shl(&sum, 1); + } + + mi_swap(&sum, m1); + mi_free(&sum); +} + +void +mi_div(struct maxint *mul, struct maxint *urem, const struct maxint *div) +{ + struct maxint orig = { 0 }, tmp = { 0 }, irem = { 0 }, *rem; + size_t i, k; + + rem = (urem == NULL) ? &irem : urem; + + mi_swap(&orig, mul); + mi_setv(mul, 0, MI_POS); + mi_setv(rem, 0, MI_POS); + for (i = 0; i < orig.size * MI_ULBITS; i++) { + k = orig.size * MI_ULBITS - 1 - i; + // rem = rem * 2 + [bit set] + mi_shl(rem, 1); + if (MI_BITA(orig.data, MI_ULBITS, k)) + mi_add(rem, mi_imm(&tmp, 1, MI_POS)); + + // mul = 2 * mul + [rem >= div] + mi_shl(mul, 1); + //printf(".\n"); + //printf("%li %li %li\n", k, rem->data[0], mul->data[0]); + if (mi_cmp(rem, div) >= 0) { + mi_add(mul, mi_imm(&tmp, 1, MI_POS)); + mi_sub(rem, div); + } + //printf("%li %li %li\n", k, rem->data[0], mul->data[0]); + } + + if (orig.sign != div->sign) + mi_sub(rem, div); + rem->sign = div->sign; + mul->sign = orig.sign ^ div->sign; + + mi_free(&orig); + if (rem == &irem) + mi_free(&irem); +} + +void +mi_set(struct maxint *m1, const struct maxint *m2) +{ + if (m1->size < m2->size) + mi_resize(m1, m2->size); + memcpy(m1->data, m2->data, m2->size * MI_ULBYTES); + if (m1->size > m2->size) + memset(m1->data + m2->size * MI_ULBYTES, 0, + (m1->size - m2->size) * MI_ULBYTES); + m1->sign = m2->sign; +} + +void +mi_setv(struct maxint *m1, mi_ul v, int sign) +{ + if (m1->size < 1) { + m1->data = chkp(malloc(MI_ULBYTES)); + m1->size = 1; + } + m1->data[0] = v; + m1->sign = sign; +} + +void +mi_swap(struct maxint *m1, struct maxint *m2) +{ + MI_SWAP(m1->data, m2->data); + MI_SWAP(m1->size, m2->size); + MI_SWAP(m1->imm, m2->imm); + MI_SWAP(m1->sign, m2->sign); +} + +void +mi_resize(struct maxint *m1, size_t size) +{ + m1->data = chkp(realloc(m1->data, size * MI_ULBYTES)); + if (size > m1->size) + memset(&m1->data[m1->size], 0, (size - m1->size) * MI_ULBYTES); + m1->size = size; +} + +const struct maxint* +mi_imm(struct maxint *dst, mi_ul v, int sign) +{ + dst->imm = v; + dst->data = &(dst->imm); + dst->size = 1; + dst->sign = sign; + return dst; +} + +mi_ul +mi_cast_ul(const struct maxint *m1) +{ + return m1->data[0]; +} + +void +mi_free(struct maxint *m1) +{ + free(m1->data); + m1->data = NULL; + m1->size = 0; +} + +int +mi_zero(const struct maxint *m1) +{ + size_t i; + + for (i = 0; i < m1->size; i++) + if (m1->data[i] != 0) return 0; + return 1; +} + +char* +mi_convstr(const struct maxint *m1, int base, const char *alph) +{ + struct maxint num = { 0 }, rem = { 0 }, tmp = { 0 }; + size_t i, k, rest, slen, scap; + char *strbuf; + int carry; + + if (base <= 1) return chkp(strdup("")); + + mi_set(&num, m1); + mi_setv(&rem, 0, MI_POS); + + scap = 16; + slen = 0; + strbuf = malloc(scap); + + do { + mi_div(&num, &rem, mi_imm(&tmp, base, MI_POS)); + rest = mi_cast_ul(&rem); + + strbuf[slen] = alph[rest]; + slen++; + if (slen >= scap) { + scap *= 2; + strbuf = realloc(strbuf, scap); + } + } while (!mi_zero(&num)); + + for (i = 0; i < slen / 2; i++) + MI_SWAP(strbuf[i], strbuf[slen - 1 - i]); + strbuf[slen] = '\0'; + + mi_free(&rem); + mi_free(&num); + + return strbuf; +} + +char* +mi_hexstr(const struct maxint *m1, int cap) +{ + return mi_convstr(m1, 16, cap ? "0123456789ABCDEF" : "0123456789abcdef"); +} + +char* +mi_decstr(const struct maxint *m1) +{ + return mi_convstr(m1, 10, "0123456789"); +} + diff --git a/libs/src/util.c b/libs/src/util.c @@ -50,7 +50,7 @@ max(int a, int b) } void* -assertp(void *alloc) +chkp(void *alloc) { if (!alloc) die("Out of Memory\n"); return alloc; @@ -61,7 +61,7 @@ memdup(void *data, size_t size) { void *new; - new = assertp(malloc(size)); + new = chkp(malloc(size)); memcpy(new, data, size); return new; } @@ -71,14 +71,14 @@ readall(int fileno, void **data, size_t *totalread) { size_t allocsize = 10, want = allocsize, got; - *data = assertp(malloc(allocsize)); + *data = chkp(malloc(allocsize)); *totalread = 0; while ((got = read(fileno, *data + *totalread, want)) > 0) { if (got == want) { allocsize *= 2; *totalread += got; - *data = assertp(realloc(*data, allocsize)); + *data = chkp(realloc(*data, allocsize)); } else { *totalread += got; } diff --git a/libs/tests/maxint.c b/libs/tests/maxint.c @@ -0,0 +1,23 @@ +#include "maxint.h" + +int +main() +{ + struct maxint a = { 0 }, b = { 0 }; + char *s1, *s2; + + mi_setv(&a, -1, MI_POS); + mi_setv(&b, 33, MI_POS); + printf("%lu / %lu = ", a.data[0], b.data[0]); + mi_div(&a, NULL, &b); + printf("%lu\n", a.data[0]); + + printf("DEC: %s\n", (s1 = mi_convstr(&a, 10, "0123456789"))); + printf("HEX: %s\n", (s2 = mi_convstr(&a, 16, "0123456789ABCDEF"))); + + mi_free(&a); + mi_free(&b); + + free(s1); + free(s2); +} diff --git a/src/day1/main.c b/src/day1/main.c @@ -2,8 +2,7 @@ #include <stdio.h> #include <string.h> -#include "partinfo.h" -#include "util.h" +#include "aoc.h" void part1(struct partinfo *p) diff --git a/src/day2/main.c b/src/day2/main.c @@ -1,8 +1,7 @@ #include <stdlib.h> #include <stdio.h> -#include "partinfo.h" -#include "util.h" +#include "aoc.h" #include "icc.h" void @@ -14,7 +13,7 @@ part1(struct partinfo *p) assert(OK, icc_parse_inst(&config, p->input, p->input_size)); icc_set_inst(&config, 1, 12); - icc_set_inst(&config, 2, 02); + icc_set_inst(&config, 2, 2); while (config.status != ICC_HALT) { icc_step_inst(&config);