diff --git a/Makefile b/Makefile index 0b1e840..ae99f38 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ TARGET = usage TEST_V_TARGET = test_vector TEST_M_TARGET = test_map -LIB_OBJS = $(OBJ_DIR)/vector.o $(OBJ_DIR)/map.o +LIB_OBJS = $(OBJ_DIR)/vector.o $(OBJ_DIR)/map.o $(OBJ_DIR)/bigint.o PROG_OBJS = $(OBJ_DIR)/usage.o .PHONY: all clean diff --git a/README.md b/README.md index 303eb64..1f29857 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,12 @@ the standard library. It currently features: - [**Vector**](/docs/vector.md): a growable, contiguous array of homogenous generic data types; - [**Map**](/docs/map.md): an associative array that handles generic heterogenous data types; +- [**BigInt**](/docs/bigint.md): a data type for arbitrary large integers. ## Usage At its simplest, you can use this library as follows: -### `Vector`'s usage +### `Vector` usage ```c #include @@ -51,7 +52,7 @@ int main(void) { } ``` -### `Map`'s usage +### `Map` usage ```c #include @@ -95,6 +96,40 @@ int main(void) { } ``` +### `BigInt` usage +```c +#include +#include "src/bigint.h" + +/* + * Compile with: gcc main.c src/bigint.c + * Output: 20000! = 1819206320230345134827641... + * Time: real 0m5.482s user 0m5.453s sys 0m0.017 + */ +int main(void) { + const int n = 20000; + bigint_t *fact = bigint_from_int(1).value.number; + + for (int idx = 2; idx<=n; idx++) { + bigint_t *big_idx = bigint_from_int(idx).value.number; + bigint_t *partial_fact = bigint_prod(fact, big_idx).value.number; + + bigint_destroy(fact); + bigint_destroy(big_idx); + fact = partial_fact; + } + + printf("%ld! = ", n); + bigint_print(fact); + printf("\n"); + + bigint_destroy(fact); + return 0; +} +``` + + + For a more exhaustive example, refer to the `usage.c` file. There, you will find a program with proper error management and a sample usage for every available method. To run it, first issue the following command: diff --git a/src/bignum.c b/src/bigint.c similarity index 86% rename from src/bignum.c rename to src/bigint.c index 10c5601..a2d6ac3 100644 --- a/src/bignum.c +++ b/src/bigint.c @@ -11,11 +11,19 @@ #define IS_DIGIT(c) ((c) >= '0') && ((c) <= '9') +#define DESTROY_IF(p) \ + do { \ + if ((p) && (p) != result.value.number) { \ + bigint_destroy((p)); \ + (p) = NULL; \ + } \ + } while (0) + #include #include #include -#include "bignum.h" +#include "bigint.h" #include "vector.h" // Internal methods @@ -96,6 +104,254 @@ bigint_result_t bigint_from_int(long long value) { 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 = BIGINT_ERR_INVALID; + SET_MSG(result, "Invalid string"); + + return result; + } + + bigint_t *number = malloc(sizeof(bigint_t)); + if (number == NULL) { + result.status = BIGINT_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 = BIGINT_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 = BIGINT_ERR_ALLOCATE; + SET_MSG(result, "Invalid integer"); + + return result; + } + + // Check whether characters are digits + for (const char *p = string_num; *p; ++p) { + if (!IS_DIGIT((unsigned char)*p)) { + vector_destroy(number->digits); + free(number); + result.status = BIGINT_ERR_INVALID; + 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'); + digit = 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 = BIGINT_ERR_ALLOCATE; + COPY_MSG(result, push_res.message); + + return result; + } + } + + bigint_result_t trim_res = bigint_trim_zeros(number); + if (trim_res.status != BIGINT_OK) { + vector_destroy(number->digits); + free(number); + + return trim_res; + } + + result.value.number = number; + result.status = BIGINT_OK; + SET_MSG(result, "Big integer successfully created"); + + return result; +} + +/** + * bigint_to_string + * @number: a valid non-null big number + * + * Converts a big integer to a C string + * + * Returns a bigint_result_t data type + */ +bigint_result_t bigint_to_string(const bigint_t *number) { + bigint_result_t result = {0}; + + if (number == NULL) { + result.status = BIGINT_ERR_INVALID; + SET_MSG(result, "Invalid big integer"); + + return result; + } + + const size_t size = vector_size(number->digits); + const size_t max_len = (size * BIGINT_BASE_DIGITS) + 2; // +2 for sign and terminator + + char *str = malloc(max_len); + if (str == NULL) { + result.status = BIGINT_ERR_ALLOCATE; + SET_MSG(result, "Failed to allocate memory for string"); + + return result; + } + + char *ptr = str; + if (number->is_negative) { + *ptr++ = '-'; + } + + // Print MSB without leading zeros + vector_result_t msb_res = vector_get(number->digits, size - 1); + if (msb_res.status != VECTOR_OK) { + result.status = BIGINT_ERR_INVALID; + COPY_MSG(result, msb_res.message); + + return result; + } + + int *msb = (int*)msb_res.value.element; + ptr += sprintf(ptr, "%d", *msb); + + // Print remaining digits with leading zeros + for (int idx = size - 2; idx >= 0; idx--) { + vector_result_t digit_res = vector_get(number->digits, idx); + if (digit_res.status != VECTOR_OK) { + result.status = BIGINT_ERR_INVALID; + COPY_MSG(result, digit_res.message); + + return result; + } + + int *digit = (int*)digit_res.value.element; + ptr += sprintf(ptr, "%09d", *digit); + } + + result.value.string_num = str; + result.status = BIGINT_OK; + SET_MSG(result, "Big integer successfully converted"); + + return result; +} + +/** + * bigint_clone + * @number: a valid non-null big integer + * + * Clones a big integer + * + * Returns a bigint_result_t data type containing the new big integer + */ +bigint_result_t bigint_clone(const bigint_t *number) { + bigint_result_t result = {0}; + + if (number == NULL) { + result.status = BIGINT_ERR_INVALID; + SET_MSG(result, "Invalid big integer"); + + return result; + } + + bigint_t *cloned = malloc(sizeof(bigint_t)); + if (cloned == NULL) { + result.status = BIGINT_ERR_ALLOCATE; + SET_MSG(result, "Failed to allocate memory for big integer"); + + return result; + } + + vector_result_t vec_res = vector_new(vector_size(number->digits), sizeof(int)); + if (vec_res.status != VECTOR_OK) { + free(cloned); + result.status = BIGINT_ERR_ALLOCATE; + COPY_MSG(result, vec_res.message); + + return result; + } + + cloned->digits = vec_res.value.vector; + cloned->is_negative = number->is_negative; + + // Copy digits + for (size_t idx = 0; idx < vector_size(number->digits); idx++) { + vector_result_t get_res = vector_get(number->digits, idx); + if (get_res.status != VECTOR_OK) { + vector_destroy(cloned->digits); + free(cloned); + result.status = BIGINT_ERR_INVALID; + COPY_MSG(result, get_res.message); + + return result; + } + + int *digit = (int*)get_res.value.element; + + vector_result_t push_res = vector_push(cloned->digits, digit); + if (push_res.status != VECTOR_OK) { + vector_destroy(cloned->digits); + free(cloned); + result.status = BIGINT_ERR_INVALID; + COPY_MSG(result, push_res.message); + + return result; + } + } + + result.value.number = cloned; + result.status = BIGINT_OK; + SET_MSG(result, "Big integer successfully cloned"); + + return result; +} + /** * bigint_trim_zeros * @number: a non-null big integer @@ -1011,360 +1267,83 @@ bigint_result_t bigint_karatsuba(const bigint_t *x, const bigint_t *y) { // Split the big integer at approximately half the size of the larger number const size_t pivot = (x_size > y_size ? x_size : y_size) / 2; - // Split x = x1 * BASE^pivot + x0 + // Results of each step bigint_t *x1 = NULL, *x0 = NULL; - bigint_result_t x_split_res = bigint_split(x, pivot, &x1, &x0); - if (x_split_res.status != BIGINT_OK) { - return x_split_res; - } + bigint_t *y1 = NULL, *y0 = NULL; + bigint_t *z0 = NULL, *z2 = NULL; + bigint_t *x_sum = NULL, *y_sum = NULL; + bigint_t *z1_temp = NULL, *z1_sub1 = NULL, *z1 = NULL; + bigint_t *z2_shifted = NULL, *z1_shifted = NULL; + bigint_t *temp = NULL, *product = NULL; + + bigint_result_t tmp_res = {0}; + + // Split x = x1 * BASE^pivot + x0 + tmp_res = bigint_split(x, pivot, &x1, &x0); + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } // Split y = y1 * BASE^pivot + y0 - bigint_t *y1 = NULL, *y0 = NULL; - bigint_result_t y_split_res = bigint_split(y, pivot, &y1, &y0); - if (y_split_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - - return y_split_res; - } + tmp_res = bigint_split(x, pivot, &y1, &y0); + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } // Perform karatsuba's trick - bigint_result_t z0_res = bigint_karatsuba(x0, y0); // x0 * y0 - if (z0_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); + tmp_res = bigint_karatsuba(x0, y0); // z0 = x0 * y0 + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + z0 = tmp_res.value.number; - return z0_res; - } - - bigint_result_t z2_res = bigint_karatsuba(x1, y1); // x1 * y1 - if (z2_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0_res.value.number); - - return z2_res; - } - - bigint_t *z0 = z0_res.value.number; - bigint_t *z2 = z2_res.value.number; + tmp_res = bigint_karatsuba(x1, y1); // z2 = x1 * y1 + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + z2 = tmp_res.value.number; // z1 = (x0 + x1) * (y0 + y1) - z0 - z2 - bigint_result_t x_sum_res = bigint_add(x0, x1); - if (x_sum_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); + tmp_res = bigint_add(x0, x1); // x_sum = x0 + x1 + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + x_sum = tmp_res.value.number; - return x_sum_res; - } + tmp_res = bigint_add(y0, y1); // y_sum = y0 + y1 + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + y_sum = tmp_res.value.number; - bigint_t *x_sum = x_sum_res.value.number; + tmp_res = bigint_karatsuba(x_sum, y_sum); // z1_temp = (x0 + x1) * (y0 + y1) + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + z1_temp = tmp_res.value.number; - bigint_result_t y_sum_res = bigint_add(y0, y1); - if (y_sum_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); - bigint_destroy(x_sum); + tmp_res = bigint_sub(z1_temp, z0); // z1_sub1 = z1_temp - z0 + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + z1_sub1 = tmp_res.value.number; - return y_sum_res; - } + tmp_res = bigint_sub(z1_sub1, z2); // z1 = z1_sub1 - z2 + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + z1 = tmp_res.value.number; - bigint_t *y_sum = y_sum_res.value.number; + tmp_res = bigint_shift_left(z2, 2 * pivot); // z2_shifted = z2 << (2 * pivot) + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + z2_shifted = tmp_res.value.number; - // (x0 + x1) * (y0 + y1) - bigint_result_t z1_temp_res = bigint_karatsuba(x_sum ,y_sum); - if (z1_temp_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); - bigint_destroy(x_sum); bigint_destroy(y_sum); + tmp_res = bigint_shift_left(z1, pivot); // z1_shifted = z1 << pivot + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + z1_shifted = tmp_res.value.number; - return z1_temp_res; - } + tmp_res = bigint_add(z2_shifted, z1_shifted); + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + temp = tmp_res.value.number; - bigint_t *z1_temp = z1_temp_res.value.number; - - // z1 = ... - z0 - bigint_result_t z1_sub1_res = bigint_sub(z1_temp, z0); - if (z1_sub1_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); - bigint_destroy(x_sum); bigint_destroy(y_sum); - bigint_destroy(z1_temp); - - return z1_sub1_res; - } - - bigint_t *z1_sub1 = z1_sub1_res.value.number; - - // z1 = ... - z2 - bigint_result_t z1_sub2_res = bigint_sub(z1_sub1, z2); - if (z1_sub2_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); - bigint_destroy(x_sum); bigint_destroy(y_sum); - bigint_destroy(z1_temp); bigint_destroy(z1_sub1); - - return z1_sub2_res; - } - - bigint_t *z1 = z1_sub2_res.value.number; - - // product = z^2 * BASE^(2pivot) + z1 * BASE^pivot + z0 - bigint_result_t z2_shift_res = bigint_shift_left(z2, 2*pivot); - if (z2_shift_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); - bigint_destroy(x_sum); bigint_destroy(y_sum); - bigint_destroy(z1_temp); bigint_destroy(z1_sub1); - bigint_destroy(z1); - - return z2_shift_res; - } - - bigint_result_t z1_shift_res = bigint_shift_left(z1, pivot); - if (z1_shift_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); - bigint_destroy(x_sum); bigint_destroy(y_sum); - bigint_destroy(z1_temp); bigint_destroy(z1_sub1); - bigint_destroy(z1); - - return z1_shift_res; - } - - bigint_t *z2_shifted = z2_shift_res.value.number; - bigint_t *z1_shifted = z1_shift_res.value.number; - - bigint_result_t temp_res = bigint_add(z2_shifted, z1_shifted); - if (temp_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); - bigint_destroy(x_sum); bigint_destroy(y_sum); - bigint_destroy(z1_temp); bigint_destroy(z1_sub1); - bigint_destroy(z1); bigint_destroy(z2_shifted); - bigint_destroy(z1_shifted); - - return temp_res; - } - - bigint_t *temp = temp_res.value.number; - - // product = ... + z0 - bigint_result_t product_res = bigint_add(temp, z0); - if (product_res.status != BIGINT_OK) { - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z2); - bigint_destroy(x_sum); bigint_destroy(y_sum); - bigint_destroy(z1_temp); bigint_destroy(z1_sub1); - bigint_destroy(z1); bigint_destroy(z2_shifted); - bigint_destroy(z1_shifted); bigint_destroy(temp); - - return product_res; - } - - bigint_t *product = product_res.value.number; - - // Clean allocated numbers - bigint_destroy(x1); bigint_destroy(x0); - bigint_destroy(y1); bigint_destroy(y0); - bigint_destroy(z0); bigint_destroy(z1); bigint_destroy(z2); - bigint_destroy(x_sum); bigint_destroy(y_sum); - bigint_destroy(z1_temp); bigint_destroy(z1_sub1); - bigint_destroy(z2_shifted); bigint_destroy(z1_shifted); - bigint_destroy(temp); + tmp_res = bigint_add(temp, z0); + if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; } + product = tmp_res.value.number; result.value.number = product; result.status = BIGINT_OK; SET_MSG(result, "Product between big integers was successful"); - 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 = BIGINT_ERR_INVALID; - SET_MSG(result, "Invalid string"); - - return result; - } - - bigint_t *number = malloc(sizeof(bigint_t)); - if (number == NULL) { - result.status = BIGINT_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 = BIGINT_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 = BIGINT_ERR_ALLOCATE; - SET_MSG(result, "Invalid integer"); - - return result; - } - - // Check whether characters are digits - for (const char *p = string_num; *p; ++p) { - if (!IS_DIGIT((unsigned char)*p)) { - vector_destroy(number->digits); - free(number); - result.status = BIGINT_ERR_INVALID; - 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'); - digit = 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 = BIGINT_ERR_ALLOCATE; - COPY_MSG(result, push_res.message); - - return result; - } - } - - bigint_result_t trim_res = bigint_trim_zeros(number); - if (trim_res.status != BIGINT_OK) { - vector_destroy(number->digits); - free(number); - - return trim_res; - } - - result.value.number = number; - result.status = BIGINT_OK; - SET_MSG(result, "Big integer successfully created"); - - return result; -} - -/** - * bigint_clone - * @number: a valid non-null big integer - * - * Clones a big integer - * - * Returns a bigint_result_t data type containing the new big integer - */ -bigint_result_t bigint_clone(const bigint_t *number) { - bigint_result_t result = {0}; - - if (number == NULL) { - result.status = BIGINT_ERR_INVALID; - SET_MSG(result, "Invalid big integer"); - - return result; - } - - bigint_t *cloned = malloc(sizeof(bigint_t)); - if (cloned == NULL) { - result.status = BIGINT_ERR_ALLOCATE; - SET_MSG(result, "Failed to allocate memory for big integer"); - - return result; - } - - vector_result_t vec_res = vector_new(vector_size(number->digits), sizeof(int)); - if (vec_res.status != VECTOR_OK) { - free(cloned); - result.status = BIGINT_ERR_ALLOCATE; - COPY_MSG(result, vec_res.message); - - return result; - } - - cloned->digits = vec_res.value.vector; - cloned->is_negative = number->is_negative; - - // Copy digits - for (size_t idx = 0; idx < vector_size(number->digits); idx++) { - vector_result_t get_res = vector_get(number->digits, idx); - if (get_res.status != VECTOR_OK) { - vector_destroy(cloned->digits); - free(cloned); - result.status = BIGINT_ERR_INVALID; - COPY_MSG(result, get_res.message); - - return result; - } - - int *digit = (int*)get_res.value.element; - - vector_result_t push_res = vector_push(cloned->digits, digit); - if (push_res.status != VECTOR_OK) { - vector_destroy(cloned->digits); - free(cloned); - result.status = BIGINT_ERR_INVALID; - COPY_MSG(result, push_res.message); - - return result; - } - } - - result.value.number = cloned; - result.status = BIGINT_OK; - SET_MSG(result, "Big integer successfully cloned"); +cleanup: // Destroy intermediate allocations except for the product + DESTROY_IF(x1); DESTROY_IF(x0); + DESTROY_IF(y1); DESTROY_IF(y0); + DESTROY_IF(z0); DESTROY_IF(z2); + DESTROY_IF(x_sum); DESTROY_IF(y_sum); + DESTROY_IF(z1_temp); DESTROY_IF(z1_sub1); DESTROY_IF(z1); + DESTROY_IF(z2_shifted); DESTROY_IF(z1_shifted); + DESTROY_IF(temp); return result; } @@ -1393,5 +1372,32 @@ bigint_result_t bigint_destroy(bigint_t *number) { result.status = BIGINT_OK; SET_MSG(result, "Big integer successfully deleted"); + return result; +} + +/** + * bigint_print + * @number: a valid non-null big integer + * + * Prints @number to standard output + * + * Returns a bigint_result_t data type + */ +bigint_result_t bigint_print(const bigint_t *number) { + bigint_result_t result = {0}; + + bigint_result_t num_str_res = bigint_to_string(number); + if (num_str_res.status != BIGINT_OK) { + return num_str_res; + } + + char *number_str = num_str_res.value.string_num; + + printf("%s", number_str); + free(number_str); + + result.status = BIGINT_OK; + SET_MSG(result, "Big integer successfully printed"); + return result; } \ No newline at end of file diff --git a/src/bignum.h b/src/bigint.h similarity index 87% rename from src/bignum.h rename to src/bigint.h index 483251a..dc06267 100644 --- a/src/bignum.h +++ b/src/bigint.h @@ -1,5 +1,5 @@ -#ifndef BIGNUM_H -#define BIGNUM_H +#ifndef BIGINT_H +#define BIGINT_H #define RESULT_MSG_SIZE 64 @@ -9,10 +9,9 @@ #define BIGINT_BASE_DIGITS 9 #include +#include #include "vector.h" -typedef enum { false = 0x0, true } bool; - typedef enum { BIGINT_OK = 0x0, BIGINT_ERR_ALLOCATE, @@ -41,12 +40,14 @@ extern "C" { bigint_result_t bigint_from_int(long long value); bigint_result_t bigint_from_string(const char *string_num); +bigint_result_t bigint_to_string(const bigint_t *number); bigint_result_t bigint_clone(const bigint_t *number); bigint_result_t bigint_compare(const bigint_t *x, const bigint_t *y); bigint_result_t bigint_add(const bigint_t *x, const bigint_t *y); bigint_result_t bigint_sub(const bigint_t *x, const bigint_t *y); bigint_result_t bigint_prod(const bigint_t *x, const bigint_t *y); bigint_result_t bigint_destroy(bigint_t *number); +bigint_result_t bigint_print(const bigint_t *number); #ifdef __cplusplus } diff --git a/usage.c b/usage.c index eec26ee..a121518 100644 --- a/usage.c +++ b/usage.c @@ -20,9 +20,12 @@ #include "src/vector.h" #include "src/map.h" +#include "src/bigint.h" static int vector_usage(); static int map_usage(); +static int bigint_usage(); + static vector_order_t cmp_int_asc(const void *x, const void *y); int main(void) { @@ -36,6 +39,11 @@ int main(void) { st = map_usage(); if (st) { return st; } + SEP(50); + + st = bigint_usage(); + if (st) { return st; } + return 0; } @@ -282,6 +290,8 @@ int map_usage() { printf("Map cleared (size should be 0): %zu\n", map_size(map)); } + printf("\n"); + // Delete the map map_result_t del_res = map_destroy(map); if (del_res.status != MAP_OK) { @@ -292,3 +302,73 @@ int map_usage() { return 0; } + +int bigint_usage() { + // Create a big integer + bigint_result_t x_res = bigint_from_string("123456789"); + if (x_res.status != BIGINT_OK) { + printf("Error while creating big number: %s\n", x_res.message); + + return 1; + } + + bigint_result_t y_res = bigint_from_string("987654321"); + if (x_res.status != BIGINT_OK) { + printf("Error while creating big number: %s\n", x_res.message); + + return 1; + } + + bigint_t *x = x_res.value.number; + bigint_t *y = y_res.value.number; + + // Sum two big integers + bigint_result_t sum_res = bigint_add(x, y); + if (sum_res.status != BIGINT_OK) { + printf("Error while summing two big numbers: %s\n", sum_res.message); + + return 1; + } + + bigint_t *sum = sum_res.value.number; + + // Print result + printf("123456789 + 987654321 (should be 1,111,111,110) = "); + bigint_print(sum); + printf("\n"); + + // Subtract two big integers + bigint_result_t diff_res = bigint_sub(x, y); + if (diff_res.status != BIGINT_OK) { + printf("Error while subtracting two big numbers: %s\n", diff_res.message); + + return 1; + } + + bigint_t *diff = diff_res.value.number; + + // Print result + printf("123456789 - 987654321 (should be -864,197,532) = "); + bigint_print(diff); + printf("\n"); + + // Multiply two big integers + bigint_result_t prod_res = bigint_prod(x, y); + if (prod_res.status != BIGINT_OK) { + printf("Error while multiplying two big numbers: %s\n", prod_res.message); + + return 1; + } + + bigint_t *prod = prod_res.value.number; + + // Print result + printf("123456789 * 987654321 (should be 121,932,631,112,635,269) = "); + bigint_print(prod); + printf("\n"); + + bigint_destroy(x); bigint_destroy(y); + bigint_destroy(sum); bigint_destroy(diff); bigint_destroy(prod); + + return 0; +} \ No newline at end of file