From 4240f5db66dcce06885a1795bcf349bd63b66936 Mon Sep 17 00:00:00 2001 From: Marco Cetica Date: Mon, 10 Nov 2025 16:23:50 +0100 Subject: [PATCH] Started 'bigint_t' implementation --- src/bignum.c | 272 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/bignum.h | 49 ++++++++++ src/map.c | 4 +- src/vector.c | 4 +- usage.c | 2 +- 5 files changed, 328 insertions(+), 3 deletions(-) create mode 100644 src/bignum.c create mode 100644 src/bignum.h diff --git a/src/bignum.c b/src/bignum.c new file mode 100644 index 0000000..d7637b1 --- /dev/null +++ b/src/bignum.c @@ -0,0 +1,272 @@ +#define SET_MSG(result, msg) \ + do { \ + snprintf((char *)(result).message, RESULT_MSG_SIZE, "%s", (const char *)msg); \ + } while (0) + +#define COPY_MSG(result, msg) \ + do { \ + strncpy((char *)(result).message, (const char *)(msg), RESULT_MSG_SIZE - 1); \ + (result).message[RESULT_MSG_SIZE - 1] = '\0'; \ + } while (0) + +#include +#include +#include + +#include "bignum.h" +#include "vector.h" + +// Internal methods +static bigint_result_t bigint_trim_zeros(bigint_t *number); + +/** + * bigint_from_int + * @value: an integer value + * + * Takes an integer and convert it to a big integer + * + * Returns a big_int_result_t data type containing a new big integer + */ +bigint_result_t bigint_from_int(long long value) { + bigint_result_t result = {0}; + + bigint_t *number = malloc(sizeof(bigint_t)); + if (number == NULL) { + result.status = BIGNUM_ERR_ALLOCATE; + SET_MSG(result, "Failed to allocate memory for big integer"); + + return result; + } + + vector_result_t vec_res = vector_new(4, sizeof(int)); + if (vec_res.status != VECTOR_OK) { + free(number); + result.status = BIGNUM_ERR_ALLOCATE; + COPY_MSG(result, vec_res.message); + + return result; + } + + number->digits = vec_res.value.vector; + number->is_negative = (value < 0); + + if (value < 0) { + value = -value; + } else if (value == 0) { + int zero = 0; + vector_result_t push_res = vector_push(number->digits, &zero); + if (push_res.status != VECTOR_OK) { + vector_destroy(number->digits); + free(number); + result.status = BIGNUM_ERR_INVALID; + COPY_MSG(result, vec_res.message); + + return result; + } + } else { + while (value > 0) { + int digit = value % BIGINT_BASE; + vector_result_t push_res = vector_push(number->digits, &digit); + if (push_res.status != VECTOR_OK) { + vector_destroy(number->digits); + free(number); + result.status = BIGNUM_ERR_INVALID; + COPY_MSG(result, vec_res.message); + + return result; + } + + value /= BIGINT_BASE; + } + } + + result.status = BIGNUM_OK; + SET_MSG(result, "Big integer successfully created"); + result.value.number = number; + + return result; +} + +/** + * bigint_trim_zeros + * @number: a non-null big integer + * + * Helper function to remove leading zeros + * + * Returns a bigint_result_t data type + */ +static bigint_result_t bigint_trim_zeros(bigint_t *number) { + bigint_result_t result = {0}; + + size_t number_len = vector_size(number->digits); + + while (number_len > 1) { + vector_result_t get_res = vector_get(number->digits, number_len - 1); + if (get_res.status != VECTOR_OK) { + vector_destroy(number->digits); + free(number); + result.status = BIGNUM_ERR_INVALID; + COPY_MSG(result, get_res.message); + + return result; + } + + int *last = (int*)get_res.value.element; + if (*last != 0) { + break; + } + + vector_result_t pop_res = vector_pop(number->digits); + if (pop_res.status != VECTOR_OK) { + vector_destroy(number->digits); + free(number); + result.status = BIGNUM_ERR_INVALID; + COPY_MSG(result, get_res.message); + + return result; + } + number_len--; + } + + if (number_len == 1) { + vector_result_t get_res = vector_get(number->digits, number_len - 1); + if (get_res.status != VECTOR_OK) { + vector_destroy(number->digits); + free(number); + result.status = BIGNUM_ERR_INVALID; + COPY_MSG(result, get_res.message); + + return result; + } + + int *first = (int*)get_res.value.element; + if (*first == 0) { + number->is_negative = false; + } + } + + result.status = BIGNUM_OK; + SET_MSG(result, "Big integer successfully trimmed"); + + return result; + +} + +/** + * bigint_from_string + * @string_num: an array of chars representing a number + * + * Takes a string containing a number and convert it to big integer + * + * Returns a bigint_result_t data type containing a new big integer + */ +bigint_result_t bigint_from_string(const char *string_num) { + bigint_result_t result = {0}; + + if (string_num == NULL || *string_num == 0) { + result.status = BIGNUM_ERR_INVALID; + SET_MSG(result, "Invalid string"); + + return result; + } + + bigint_t *number = malloc(sizeof(bigint_t)); + if (number == NULL) { + result.status = BIGNUM_ERR_ALLOCATE; + SET_MSG(result, "Failed to allocate memory for big integer"); + + return result; + } + + vector_result_t vec_res = vector_new(4, sizeof(int)); + if (vec_res.status != VECTOR_OK) { + vector_destroy(number->digits); + free(number); + result.status = BIGNUM_ERR_ALLOCATE; + COPY_MSG(result, vec_res.message); + + return result; + } + + number->digits = vec_res.value.vector; + + number->is_negative = false; + if (*string_num == '-') { + number->is_negative = true; + string_num++; + } else if (*string_num == '+') { + string_num++; + } + + // Check whether the integer is valid or not + if (*string_num == '\0') { + vector_destroy(number->digits); + free(number); + result.status = BIGNUM_ERR_ALLOCATE; + SET_MSG(result, "Invalid integer"); + + return result; + } + + // Skip leading zeros + while (*string_num == '0' && *(string_num + 1) != '\0') { + string_num++; + } + + const size_t number_len = strlen(string_num); + + // Process digits from right to left by chunks of the representation base + for (int i = number_len; i > 0; i -= BIGINT_BASE_DIGITS) { + const int start = (i - BIGINT_BASE_DIGITS > 0) ? i - BIGINT_BASE_DIGITS : 0; + const int chunk_len = (i - start); + + int digit = 0; + for (int j = 0; j < chunk_len; j++) { + digit *= 10 + (string_num[start + j] - '0'); + } + + vector_result_t push_res = vector_push(number->digits, &digit); + if (push_res.status != VECTOR_OK) { + vector_destroy(number->digits); + free(number); + result.status = BIGNUM_ERR_ALLOCATE; + COPY_MSG(result, vec_res.message); + + return result; + } + } + + bigint_trim_zeros(number); + + result.status = BIGNUM_OK; + SET_MSG(result, "Big integer successfully created"); + + return result; +} + +/** + * bigint_destroy + * @number: a valid big integer + * + * Deletes the big integer from the memory + * + * Returns a bigint_result_t data type + */ +bigint_result_t bigint_destroy(bigint_t *number) { + bigint_result_t result = {0}; + + if (number == NULL) { + result.status = BIGNUM_ERR_INVALID; + SET_MSG(result, "Invalid big integer"); + + return result; + } + + vector_destroy(number->digits); + free(number); + + result.status = BIGNUM_OK; + SET_MSG(result, "Big integer successfully deleted"); + + return result; +} \ No newline at end of file diff --git a/src/bignum.h b/src/bignum.h new file mode 100644 index 0000000..07de64b --- /dev/null +++ b/src/bignum.h @@ -0,0 +1,49 @@ +#ifndef BIGNUM_H +#define BIGNUM_H + +#define RESULT_MSG_SIZE 64 + +// Big numbers numerical base (10^9) +#define BIGINT_BASE 1000000000 +// Each digit stores values from 0 to 999,999,999 +#define BIGINT_BASE_DIGITS 9 + +#include +#include "vector.h" + +typedef enum { false = 0x0, true } bool; + +typedef enum { + BIGNUM_OK = 0x0, + BIGNUM_ERR_ALLOCATE, + BIGNUM_ERR_DIV_BY_ZERO, + BIGNUM_ERR_INVALID +} bignum_status_t; + +typedef struct { + vector_t *digits; + bool is_negative; +} bigint_t; + +typedef struct { + bignum_status_t status; + uint8_t message[RESULT_MSG_SIZE]; + union { + bigint_t *number; + char *string_num; + } value; +} bigint_result_t; + +#ifdef __cplusplus +extern "C" { +#endif + +bigint_result_t bigint_from_int(long long value); +bigint_result_t bigint_from_string(const char *string_num); +bigint_result_t bigint_destroy(bigint_t *number); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/map.c b/src/map.c index d752697..88a3887 100644 --- a/src/map.c +++ b/src/map.c @@ -1,5 +1,7 @@ #define SET_MSG(result, msg) \ - snprintf((char *)result.message, RESULT_MSG_SIZE, msg) + do { \ + snprintf((char *)(result).message, RESULT_MSG_SIZE, "%s", (const char *)msg); \ + } while (0) #include #include diff --git a/src/vector.c b/src/vector.c index 8eb8d85..089b750 100644 --- a/src/vector.c +++ b/src/vector.c @@ -1,5 +1,7 @@ #define SET_MSG(result, msg) \ - snprintf((char *)result.message, RESULT_MSG_SIZE, msg) + do { \ + snprintf((char *)(result).message, RESULT_MSG_SIZE, "%s", (const char *)msg); \ + } while (0) #include #include diff --git a/usage.c b/usage.c index c0f561c..eec26ee 100644 --- a/usage.c +++ b/usage.c @@ -225,7 +225,7 @@ int map_usage() { // Print size and capacity printf("Map size (should be 2): %zu\n", map_size(map)); - printf("Map capacity (should be >=2): %zu\n\n", map_capacity(map)); + printf("Map capacity (should be > 2): %zu\n\n", map_capacity(map)); // Retrieve keys map_result_t get_res = map_get(map, "x");