diff --git a/.github/workflows/clang-build.yml b/.github/workflows/clang-build.yml
new file mode 100644
index 0000000..1e7b286
--- /dev/null
+++ b/.github/workflows/clang-build.yml
@@ -0,0 +1,19 @@
+name: clang-build
+on: [push,pull_request,workflow_dispatch]
+
+jobs:
+ clang-build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install Clang
+ run: sudo apt update && sudo apt install -y clang
+
+ - name: Build Datum
+ run: |
+ make clean all CC=clang
+
+ - name: Run unit tests
+ run: |
+ ./test_vector && ./test_map && ./test_bigint
\ No newline at end of file
diff --git a/.github/workflows/datum.yml b/.github/workflows/gcc-build.yml
similarity index 59%
rename from .github/workflows/datum.yml
rename to .github/workflows/gcc-build.yml
index 4f25837..b277691 100644
--- a/.github/workflows/datum.yml
+++ b/.github/workflows/gcc-build.yml
@@ -1,17 +1,16 @@
-name: datum
-on:
- push:
- branch: [master]
- workflow_dispatch:
+name: gcc-build
+on: [push,pull_request,workflow_dispatch]
jobs:
- build:
+ gcc-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
+
- name: Build Datum
run: |
make clean all
+
- name: Run unit tests
run: |
- ./test_vector && ./test_map
\ No newline at end of file
+ ./test_vector && ./test_map && ./test_bigint
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 0b1e840..b0152f4 100644
--- a/Makefile
+++ b/Makefile
@@ -10,13 +10,14 @@ TESTS_SRC = tests
TARGET = usage
TEST_V_TARGET = test_vector
TEST_M_TARGET = test_map
+TEST_B_TARGET = test_bigint
-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
-all: $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET)
+all: $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) $(TEST_B_TARGET)
$(TARGET): $(PROG_OBJS) $(LIB_OBJS)
$(CC) $(CFLAGS) -o $@ $^
@@ -27,6 +28,9 @@ $(TEST_V_TARGET): $(OBJ_DIR)/test_vector.o $(OBJ_DIR)/vector.o
$(TEST_M_TARGET): $(OBJ_DIR)/test_map.o $(OBJ_DIR)/map.o
$(CC) $(CFLAGS) -o $@ $^
+$(TEST_B_TARGET): $(OBJ_DIR)/test_bigint.o $(OBJ_DIR)/bigint.o $(OBJ_DIR)/vector.o
+ $(CC) $(CFLAGS) -o $@ $^
+
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CFLAGS) -c -o $@ $<
@@ -40,4 +44,4 @@ $(OBJ_DIR):
mkdir -p $(OBJ_DIR)
clean:
- rm -rf $(OBJ_DIR) $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET)
+ rm -rf $(OBJ_DIR) $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) $(TEST_B_TARGET)
diff --git a/README.md b/README.md
index 412afa9..95b1dc5 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,8 @@
Datum
Collection of dynamic and generic data structures.
-[](https://github.com/ceticamarco/datum/actions/workflows/datum.yml)
+[](https://github.com/ceticamarco/datum/actions/workflows/gcc-build.yml)
+[](https://github.com/ceticamarco/datum/actions/workflows/clang-build.yml)
Datum is a collection of dynamic and generic data structures implemented from scratch in C with no external dependencies beyond
@@ -10,11 +11,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 +53,7 @@ int main(void) {
}
```
-### `Map`'s usage
+### `Map` usage
```c
#include
@@ -95,6 +97,35 @@ int main(void) {
}
```
+### `BigInt` usage
+```c
+#include "src/bigint.h"
+
+/*
+ * Compile with: gcc -O3 main.c src/bigint.c src/vector.c
+ * Output: 20000! = 1819206320230345134827641...
+ * Time: 4.01s user 0.00s system 99% cpu 4.021 total
+ */
+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;
+ }
+
+ bigint_printf("%d! = %B\n", n, fact);
+
+ 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:
@@ -109,12 +140,13 @@ For additional details about this library (internal design, memory
management, data ownership, etc.) go to the [docs folder](/docs).
## Unit tests
-Datum provides some unit tests for both the `Vector` and the `Map` data types. To run them, you can issue the following commands:
+Datum provides some unit tests for `Vector`, `Map` and `BigInt`. To run them, you can issue the following commands:
```sh
$ make clean all
$ ./test_vector
$ ./test_map
+$ ./test_bigint
```
## License
diff --git a/docs/README.md b/docs/README.md
index 6483877..f7e6320 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -7,5 +7,5 @@ At the time being, this documentation includes the following pages:
- [vector.md](vector.md): vector documentation;
- [map.md](map.md): map documentation;
-- [sort.md](sort.md): how to use the `vector_sort` method.
-
+- [sort.md](sort.md): how to use the `vector_sort` method;
+- [bigint.md](bigint.md): bigint documentation.
diff --git a/docs/bigint.md b/docs/bigint.md
new file mode 100644
index 0000000..3f07731
--- /dev/null
+++ b/docs/bigint.md
@@ -0,0 +1,92 @@
+# BigInt Technical Details
+In this document you can find a quick overview of the technical
+aspects (internal design, memory layout, etc.) of the `BigInt` data structure.
+
+`BigInt` is a data type for arbitrary precision arithmetic that supports addition,
+subtraction, multiplication, division and modulo operations on signed integers of unlimited size. Internally, it uses
+the `Vector` data structure to represent big numbers using the following layout:
+
+```
+Number: 2485795518678991171206065
+Internally: [ 171206065, 518678991, 2485795 ]
+ / | \
+ / | \
+ digit[0] digit[1] digit[2]
+ (LSB) (MSB)
+```
+
+That is, each element of the vector stores 9 digits in base $10^9$ using
+**little-endian order**. Each such digits can therefore store values from `0` up to
+`999,999,999`.
+
+This scheme maps to the following structure:
+
+```c
+typedef struct {
+ vector_t *digits;
+ bool is_negative;
+} bigint_t;
+```
+
+where the `digits` array stores the representation in base $10^9$ of the big integer
+and the boolean `is_negative` variable denotes its sign.
+
+The `BigInt` data structure supports the following methods:
+
+- `bigint_result_t bigint_from_int(value)`: create a big integer from a primitive `int` type;
+- `bigint_result_t bigint_from_string(string_num)`: create a big integer from a C string;
+- `bigint_result_t bigint_to_string(number)`: convert a big integer to a C string;
+- `bigint_result_t bigint_clone(number)`: clone a big integer;
+- `bigint_result_t bigint_compare(x, y)`: compare two big integers, returning either `-1`, `0` or `1` if the first is less than, equal than or greater than the second, respectively;
+- `bigint_result_t bigint_add(x, y)`: add two big integers together in $\mathcal{O}(n)$;
+- `bigint_result_t bigint_sub(x, y)`: subtract two big integers in $\mathcal{O}(n)$;
+- `bigint_result_t bigint_prod(x, y)`: multiply two big integers using Karatsuba's algorithm in $\mathcal{O}(n^{1.585})$;
+- `bigint_result_t bigint_divmod(x, y)`: divide two big integers using *long division* algorithm in $\mathcal{O}(n^2)$, returning both the quotient and the remainder;
+- `bigint_result_t bigint_mod(x, y)`: computes modulo of two big integers using *long division* algorithm in $\mathcal{O}(n^2)$;
+- `bigint_result_t bigint_destroy(number)`: delete the big number;
+- `bigint_result_t bigint_printf(format, ...)`: `printf` wrapper that introduces the `%B` placeholder to print big numbers. It supports variadic parameters.
+
+As you can see by the previous function signatures, methods that operate on the
+`BigInt` data type return a custom type called `bigint_result_t` which is defined as
+follows:
+
+```c
+typedef enum {
+ BIGINT_OK = 0x0,
+ BIGINT_ERR_ALLOCATE,
+ BIGINT_ERR_DIV_BY_ZERO,
+ BIGINT_ERR_INVALID
+} bigint_status_t;
+
+typedef struct {
+ bigint_t *quotient;
+ bigint_t *remainder;
+} div_result_t;
+
+typedef struct {
+ bigint_status_t status;
+ uint8_t message[RESULT_MSG_SIZE];
+ union {
+ bigint_t *number;
+ div_result_t division;
+ int8_t compare_status;
+ char *string_num;
+ } value;
+} bigint_result_t;
+```
+
+Each method that returns such type indicates whether the operation was successful or not
+by setting the `status` field and by providing a descriptive message on the `message`
+field. If the operation was successful (that is, `status == BIGINT_OK`), you can either
+move on with the rest of the program or read the returned value from the sum data type.
+Of course, you can choose to ignore the return value (if you're brave enough :D) as
+illustrated in the first part of the README.
+
+The sum data type (i.e., the `value` union) defines four different variables. Each
+of them has an unique scope as described below:
+
+- `number`: result of arithmetical, cloning and creating functions;
+- `division`: result of `bigint_divmod`;
+- `compare_status`: result of `bigint_compare`;
+- `string_num`: result of `bigint_to_string`.
+
diff --git a/docs/map.md b/docs/map.md
index f061d10..02471b1 100644
--- a/docs/map.md
+++ b/docs/map.md
@@ -71,5 +71,5 @@ typedef struct {
Each method that returns such type indicates whether the operation was successful or not by setting
the `status` field and by providing a descriptive message on the `message` field. If the operation was
successful (that is, `status == MAP_OK`), you can either move on with the rest of the program or read
-the returned value from the sum data type. Of course, you can choose to ignore the return value (if you're brave enough :D), as illustrated
+the returned value from the sum data type. Of course, you can choose to ignore the return value (if you're brave enough :D) as illustrated
in the first part of the README.
\ No newline at end of file
diff --git a/docs/sort.md b/docs/sort.md
index a76c3c3..5f2f900 100644
--- a/docs/sort.md
+++ b/docs/sort.md
@@ -42,7 +42,7 @@ vector_order_t cmp_int_desc(const void *x, const void *y) {
}
/*
- * Compile with: gcc main.c src/vector.h
+ * Compile with: gcc main.c src/vector.c
* Output: Before sorting: -8 20 -10 125 34 9
* After sorting (ascending order): -10 -8 9 20 34 125
* After sorting (descending order): 125 34 20 9 -8 -10
@@ -55,9 +55,11 @@ int main(void) {
vector_push(v, &values[idx]);
}
+ const size_t sz = vector_size(v);
+
// Print unsorted array
printf("Before sorting: ");
- for (size_t idx = 0; idx < vector_size(v); idx++) {
+ for (size_t idx = 0; idx < sz; idx++) {
printf("%d ", *(int*)vector_get(v, idx).value.element);
}
@@ -66,7 +68,7 @@ int main(void) {
// Print sorted array
printf("\nAfter sorting (ascending order): ");
- for (size_t idx = 0; idx < vector_size(v); idx++) {
+ for (size_t idx = 0; idx < sz; idx++) {
printf("%d ", *(int*)vector_get(v, idx).value.element);
}
@@ -75,7 +77,7 @@ int main(void) {
// Print sorted array
printf("\nAfter sorting (descending order): ");
- for (size_t idx = 0; idx < vector_size(v); idx++) {
+ for (size_t idx = 0; idx < sz; idx++) {
printf("%d ", *(int*)vector_get(v, idx).value.element);
}
@@ -124,7 +126,7 @@ vector_order_t cmp_person_by_name(const void *x, const void *y) {
}
/*
- * Compile with: gcc main.c src/vector.h
+ * Compile with: gcc main.c src/vector.c
* Output: Sort by age:
* Name: Marco, Age: 25
* Name: Alice, Age: 28
@@ -149,9 +151,11 @@ int main(void) {
// Sort array by age
vector_sort(employees, cmp_person_by_age);
+ const size_t sz = vector_size(employees);
+
// Print sorted array
printf("Sort by age:\n");
- for (size_t idx = 0; idx < vector_size(employees); idx++) {
+ for (size_t idx = 0; idx < sz; idx++) {
Employee *p = (Employee*)vector_get(employees, idx).value.element;
printf("Name: %s, Age: %d\n", p->name, p->age);
}
@@ -161,7 +165,7 @@ int main(void) {
// Print sorted array
printf("\nSort by name:\n");
- for (size_t idx = 0; idx < vector_size(employees); idx++) {
+ for (size_t idx = 0; idx < sz; idx++) {
Employee *p = (Employee*)vector_get(employees, idx).value.element;
printf("Name: %s, Age: %d\n", p->name, p->age);
}
diff --git a/docs/vector.md b/docs/vector.md
index 477b97a..a271eef 100644
--- a/docs/vector.md
+++ b/docs/vector.md
@@ -64,7 +64,7 @@ Each method that returns such type indicates whether the operation was successfu
by setting the `status` field and by providing a descriptive message on the `message`
field. If the operation was successful (that is, `status == VECTOR_OK`), you can either
move on with the rest of the program or read the returned value from the sum data type. Of course, you can choose to
-ignore the return value (if you're brave enough :D), as illustrated in the first part of the README.
+ignore the return value (if you're brave enough :D) as illustrated in the first part of the README.
The documentation for the `vector_sort(map, cmp)` method can be found
in [the following document](/docs/sort.md).
\ No newline at end of file
diff --git a/src/bigint.c b/src/bigint.c
new file mode 100644
index 0000000..e7835b5
--- /dev/null
+++ b/src/bigint.c
@@ -0,0 +1,1863 @@
+#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)
+
+#define IS_DIGIT(c) ((c) >= '0') && ((c) <= '9')
+
+#include
+#include
+#include
+#include
+
+#include "bigint.h"
+#include "vector.h"
+
+// Internal methods
+static bigint_result_t bigint_trim_zeros(bigint_t *number);
+static bigint_result_t bigint_compare_abs(const bigint_t *x, const bigint_t *y);
+static bigint_result_t bigint_add_abs(const bigint_t *x, const bigint_t *y);
+static bigint_result_t bigint_sub_abs(const bigint_t *x, const bigint_t *y);
+static bigint_result_t bigint_shift_left(const bigint_t *num, size_t n);
+static bigint_result_t bigint_split(const bigint_t *num, size_t m, bigint_t **high, bigint_t **low);
+static bigint_result_t bigint_karatsuba_base(const bigint_t *x, const bigint_t *y);
+static bigint_result_t bigint_karatsuba(const bigint_t *x, const bigint_t *y);
+static bigint_result_t bigint_div(const bigint_t *x, const bigint_t *y);
+
+/**
+ * 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 = 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 = (value < 0);
+
+ // Discard the sign since we don't need it anymore
+ unsigned long long abs_val = value < 0 ? -(unsigned long long)value : (unsigned long long)value;
+
+ if(abs_val == 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 = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ } else {
+ while (abs_val != 0) {
+ int digit = abs_val % 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 = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+
+ abs_val /= BIGINT_BASE;
+ }
+ }
+
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integer successfully created");
+ result.value.number = number;
+
+ 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 = 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
+ const size_t sz = vector_size(number->digits);
+ for (size_t idx = 0; idx < sz; 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
+ *
+ * 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);
+ result.status = BIGINT_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);
+ result.status = BIGINT_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);
+ result.status = BIGINT_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 = BIGINT_OK;
+ SET_MSG(result, "Big integer successfully trimmed");
+
+ return result;
+
+}
+
+/**
+ * bigint_compare_abs
+ * @x: a non-null big integer
+ * @y: a non-null big integer
+ *
+ * Compares absolute value of two big integers
+ * if |x| < |y| => -1
+ * if |x| == |y| => 0
+ * if |x| > |y| => 1
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_compare_abs(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ const size_t x_size = vector_size(x->digits);
+ const size_t y_size = vector_size(y->digits);
+
+ if (x_size != y_size) {
+ result.value.compare_status = (x_size > y_size) ? 1 : -1;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integer comparison was successful");
+
+ return result;
+ }
+
+ // Start to compare from the MSB
+ for (int idx = (int)(x_size - 1); idx >= 0; idx--) {
+ vector_result_t x_get = vector_get(x->digits, idx);
+ if (x_get.status != VECTOR_OK) {
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, x_get.message);
+
+ return result;
+ }
+
+ vector_result_t y_get = vector_get(y->digits, idx);
+ if (y_get.status != VECTOR_OK) {
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, y_get.message);
+
+ return result;
+ }
+
+ int *x_digit = (int*)x_get.value.element;
+ int *y_digit = (int*)y_get.value.element;
+
+ if (*x_digit != *y_digit) {
+ result.value.compare_status = (*x_digit > *y_digit) ? 1 : -1;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integer comparison was successful");
+
+ return result;
+ }
+ }
+
+ result.value.compare_status = 0;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integer comparison was successful");
+
+ return result;
+}
+
+/**
+ * bigint_compare
+ * @x: a valid non-null big integer
+ * @y: a valid non-null big integer
+ *
+ * Compares two big integers
+ * if x < y => -1
+ * if x == y => 0
+ * if x > y => 1
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_compare(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ if (x->is_negative != y->is_negative) {
+ result.value.compare_status = x->is_negative ? -1 : 1;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integer comparison was successful");
+
+ return result;
+ }
+
+ bigint_result_t cmp_res = bigint_compare_abs(x, y);
+ if (cmp_res.status != BIGINT_OK) {
+ return cmp_res;
+ }
+
+ const int8_t abs_cmp = cmp_res.value.compare_status;
+
+ result.value.compare_status = x->is_negative ? -abs_cmp : abs_cmp;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integer comparison was successful");
+
+ return result;
+}
+
+/**
+ * bigint_add_abs
+ * @x: a non-null big integer
+ * @y: a non-null big integer
+ *
+ * Adds two absolute values together
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_add_abs(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ bigint_t *sum = malloc(sizeof(bigint_t));
+ if (sum == NULL) {
+ result.status = BIGINT_ERR_ALLOCATE;
+ SET_MSG(result, "Cannot allocate memory for big integer");
+
+ return result;
+ }
+
+ const size_t max_size = vector_size(x->digits) > vector_size(y->digits) ?
+ vector_size(x->digits) : vector_size(y->digits);
+
+ vector_result_t vec_res = vector_new(max_size + 1, sizeof(int));
+ if (vec_res.status != VECTOR_OK) {
+ free(sum);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, vec_res.message);
+
+ return result;
+ }
+
+ sum->digits = vec_res.value.vector;
+ sum->is_negative = false;
+
+ long long carry = 0;
+ size_t idx = 0;
+
+ const size_t x_size = vector_size(x->digits);
+ const size_t y_size = vector_size(y->digits);
+ while (idx < x_size || idx < y_size || carry) {
+ long long partial_sum = carry;
+
+ if (idx < x_size) {
+ vector_result_t get_res = vector_get(x->digits, idx);
+ if (get_res.status != VECTOR_OK) {
+ vector_destroy(sum->digits);
+ free(sum);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, get_res.message);
+
+ return result;
+ }
+
+ int *x_digit = (int*)get_res.value.element;
+ partial_sum += *x_digit;
+ }
+
+ if (idx < y_size) {
+ vector_result_t get_res = vector_get(y->digits, idx);
+ if (get_res.status != VECTOR_OK) {
+ vector_destroy(sum->digits);
+ free(sum);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, get_res.message);
+
+ return result;
+ }
+
+ int *y_digit = (int*)get_res.value.element;
+ partial_sum += *y_digit;
+ }
+
+ int digit = partial_sum % BIGINT_BASE;
+ carry = partial_sum / BIGINT_BASE;
+
+ vector_result_t push_res = vector_push(sum->digits, &digit);
+ if (push_res.status != VECTOR_OK) {
+ vector_destroy(sum->digits);
+ free(sum);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ idx++;
+ }
+
+ bigint_result_t trim_res = bigint_trim_zeros(sum);
+ if (trim_res.status != BIGINT_OK) {
+ vector_destroy(sum->digits);
+ free(sum);
+
+ return trim_res;
+ }
+
+ result.value.number = sum;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integers successfully added");
+
+ return result;
+}
+
+/**
+ * bigint_sub_abs
+ * @x: a non-null big integer
+ * @y: a non-null big integer
+ *
+ * Subtracts two absolute values assuming that |x| >= |y|
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_sub_abs(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ bigint_t *difference = malloc(sizeof(bigint_t));
+ if (difference == NULL) {
+ result.status = BIGINT_ERR_ALLOCATE;
+ SET_MSG(result, "Cannot allocate memory for big integer");
+
+ return result;
+ }
+
+ vector_result_t vec_res = vector_new(vector_size(x->digits), sizeof(int));
+ if (vec_res.status != VECTOR_OK) {
+ free(difference);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, vec_res.message);
+
+ return result;
+ }
+
+ difference->digits = vec_res.value.vector;
+ difference->is_negative = false;
+
+ long long borrow = 0;
+
+ const size_t x_size = vector_size(x->digits);
+ const size_t y_size = vector_size(y->digits);
+ for (size_t idx = 0; idx < x_size; idx++) {
+ vector_result_t x_get_res = vector_get(x->digits, idx);
+ if (x_get_res.status != VECTOR_OK) {
+ vector_destroy(difference->digits);
+ free(difference);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, x_get_res.message);
+
+ return result;
+ }
+
+ int *x_digit = (int*)x_get_res.value.element;
+ long long partial_difference = *x_digit - borrow;
+
+ if (idx < y_size) {
+ vector_result_t y_get_res = vector_get(y->digits, idx);
+ if (y_get_res.status != VECTOR_OK) {
+ vector_destroy(difference->digits);
+ free(difference);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, y_get_res.message);
+
+ return result;
+ }
+
+ int *y_digit = (int*)y_get_res.value.element;
+ partial_difference -= *y_digit;
+ }
+
+ if (partial_difference < 0) {
+ partial_difference += BIGINT_BASE;
+ borrow = 1;
+ } else {
+ borrow = 0;
+ }
+
+ int digit = partial_difference;
+ vector_result_t push_res = vector_push(difference->digits, &digit);
+ if (push_res.status != VECTOR_OK) {
+ vector_destroy(difference->digits);
+ free(difference);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ }
+
+ bigint_result_t trim_res = bigint_trim_zeros(difference);
+ if (trim_res.status != BIGINT_OK) {
+ vector_destroy(difference->digits);
+ free(difference);
+
+ return trim_res;
+ }
+
+ result.value.number = difference;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integers successfully subtracted");
+
+ return result;
+}
+
+/**
+ * bigint_add
+ * @x: a non-null big integer
+ * @y: a non-null big integer
+ *
+ * Adds two big integers together
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_add(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ if (x == NULL || y == NULL) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid big integers");
+
+ return result;
+ }
+
+ // Same sign: add absolute values
+ if (x->is_negative == y->is_negative) {
+ bigint_result_t sum_res = bigint_add_abs(x, y);
+ if (sum_res.status != BIGINT_OK) {
+ return sum_res;
+ }
+
+ bigint_t *sum = sum_res.value.number;
+ if (sum) {
+ sum->is_negative = x->is_negative;
+ }
+
+ result.value.number = sum;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integers successfully added");
+
+ return result;
+ }
+
+ // Different signs: subtract smaller from larger
+ bigint_result_t cmp_res = bigint_compare_abs(x, y);
+ if (cmp_res.status != BIGINT_OK) {
+ return cmp_res;
+ }
+
+ const int8_t cmp = cmp_res.value.compare_status;
+ if (cmp == 0) {
+ return bigint_from_int(0);
+ } else if (cmp > 0) {
+ bigint_result_t sub_res = bigint_sub_abs(x, y);
+ if (sub_res.status != BIGINT_OK) {
+ return sub_res;
+ }
+
+ bigint_t *sub = sub_res.value.number;
+ if (sub) {
+ sub->is_negative = x->is_negative;
+ }
+
+ result.value.number = sub;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integers successfully added");
+ } else {
+ bigint_result_t sub_res = bigint_sub_abs(y, x);
+ if (sub_res.status != BIGINT_OK) {
+ return sub_res;
+ }
+
+ bigint_t *sub = sub_res.value.number;
+ if (sub) {
+ sub->is_negative = y->is_negative;
+ }
+
+ result.value.number = sub;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integers successfully added");
+ }
+
+ return result;
+}
+
+/**
+ * bigint_sub
+ * @x: a non-null big integer
+ * @y: a non-null big integer
+ *
+ * Subtracts two big integers together
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_sub(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ if (x == NULL || y == NULL) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid big integers");
+
+ return result;
+ }
+
+ /* To subtract two big integers we can consider
+ * the following equivalence:
+ * x - y = x + (-y)
+ */
+ bigint_result_t neg_y_res = bigint_clone(y);
+ if (neg_y_res.status != BIGINT_OK) {
+ return neg_y_res;
+ }
+
+ bigint_t *neg_y = neg_y_res.value.number;
+ neg_y->is_negative = !neg_y->is_negative;
+
+ bigint_result_t difference_res = bigint_add(x, neg_y);
+ if (difference_res.status != BIGINT_OK) {
+ bigint_destroy(neg_y);
+
+ return difference_res;
+ }
+
+ bigint_destroy(neg_y);
+ bigint_t *difference = difference_res.value.number;
+
+ result.value.number = difference;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integers successfully subtracted");
+
+ return result;
+}
+
+/**
+ * bigint_prod
+ * @x: a non-null big integer
+ * @y: a non-null big integer
+ *
+ * Perform a multiplication between @a and @b
+ * using Karatsuba's algorithm
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_prod(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ if (x == NULL || y == NULL) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid big integers");
+
+ return result;
+ }
+
+ bigint_result_t product_res = bigint_karatsuba(x, y);
+ if (product_res.status != BIGINT_OK) {
+ return product_res;
+ }
+
+ bigint_t *product = product_res.value.number;
+ product->is_negative = (x->is_negative != y->is_negative);
+
+ bigint_result_t trim_res = bigint_trim_zeros(product);
+ if (trim_res.status != BIGINT_OK) {
+ bigint_destroy(product);
+
+ return trim_res;
+ }
+
+ result.value.number = product;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Product between big integers was successful");
+
+ return result;
+}
+
+
+
+/**
+ * bigint_divmod
+ * @x: a valid non-null big integer
+ * @y: a valid non-null big integer
+ *
+ * Computes division with remainder
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_divmod(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+ bigint_result_t tmp_res = {0};
+
+ // Intermediate results
+ bigint_t *quotient = NULL;
+ bigint_t *y_times_q = NULL;
+ bigint_t *remainder = NULL;
+
+ if (x == NULL || y == NULL) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid big numbers");
+
+ return result;
+ }
+
+ // Check for division by zero
+ const size_t y_size = vector_size(y->digits);
+ if (y_size == 0) {
+ result.status = BIGINT_ERR_DIV_BY_ZERO;
+ SET_MSG(result, "Division by zero");
+
+ return result;
+ }
+
+ if (y_size == 1) {
+ vector_result_t y_val_res = vector_get(y->digits, 0);
+ if (y_val_res.status != VECTOR_OK) {
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, y_val_res.message);
+
+ return result;
+ }
+
+ int *y_val = (int*)y_val_res.value.element;
+ if (*y_val == 0) {
+ result.status = BIGINT_ERR_DIV_BY_ZERO;
+ SET_MSG(result, "Division by zero");
+
+ return result;
+ }
+ }
+
+ // |x| < |y| then quotient is 0 and remainder is x
+ tmp_res = bigint_compare_abs(x, y);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+
+ if (tmp_res.value.compare_status < 0) {
+ tmp_res = bigint_from_int(0);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+ quotient = tmp_res.value.number;
+
+ tmp_res = bigint_clone(x);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+ remainder = tmp_res.value.number;
+
+ result.value.division.quotient = quotient;
+ result.value.division.remainder = remainder;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Division between big integers was successful");
+
+ return result;
+ }
+
+ tmp_res = bigint_div(x, y);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+ quotient = tmp_res.value.number;
+
+ // Compute r = x - y * q
+ tmp_res = bigint_prod(y, quotient);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+ y_times_q = tmp_res.value.number;
+
+ tmp_res = bigint_sub(x, y_times_q);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+ remainder = tmp_res.value.number;
+
+ // Ensure that remainder has correct sign (i.e., same as dividend x)
+ // In C-style division, sign(remainder) = sign(dividend)
+ remainder->is_negative = x->is_negative;
+
+ tmp_res = bigint_trim_zeros(remainder);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+
+ result.value.division.quotient = quotient;
+ result.value.division.remainder = remainder;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Division between big integers was successful");
+
+ bigint_destroy(y_times_q);
+
+ return result;
+
+cleanup:
+ if (quotient) { bigint_destroy(quotient); }
+ if (y_times_q) { bigint_destroy(y_times_q); }
+ if (remainder) { bigint_destroy(remainder); }
+
+ return result;
+}
+
+/**
+ * bigint_mod
+ * @x: a valid non-null big integer
+ * @y: a valid non-null big integer
+ *
+ * Computes @x mod @y
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_mod(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ if (x == NULL || y == NULL) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid big numbers");
+
+ return result;
+ }
+
+ bigint_result_t div_res = bigint_divmod(x, y);
+ if (div_res.status != BIGINT_OK) { return div_res; }
+
+ bigint_t* const quotient = div_res.value.division.quotient;
+ bigint_t* const remainder = div_res.value.division.remainder;
+
+ // Discard quotient
+ bigint_destroy(quotient);
+
+ result.value.number = remainder;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Division between big integers was successful");
+
+ return result;
+}
+
+/**
+ * bigint_shift_left
+ * @num: a non-null big integer
+ * @n: number of digits to shift
+ *
+ * Shifts left by @n digits (i.e., multiply by BASE^n)
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_shift_left(const bigint_t *num, size_t n) {
+ bigint_result_t result = {0};
+
+ if (n == 0) {
+ return bigint_clone(num);
+ }
+
+ bigint_t *shifted = malloc(sizeof(bigint_t));
+ if (shifted == 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(num->digits) + n, sizeof(int));
+ if (vec_res.status != VECTOR_OK) {
+ free(shifted);
+ result.status = BIGINT_ERR_ALLOCATE;
+ COPY_MSG(result, vec_res.message);
+
+ return result;
+ }
+
+ shifted->digits = vec_res.value.vector;
+ shifted->is_negative = num->is_negative;
+
+ // Add 'n' zeros by starting from the LSB
+ int zero = 0;
+ for (size_t idx = 0; idx < n; idx++) {
+ vector_result_t push_res = vector_push(shifted->digits, &zero);
+ if (push_res.status != VECTOR_OK) {
+ vector_destroy(shifted->digits);
+ free(shifted);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ }
+
+ // Copy back original digits
+ const size_t num_size = vector_size(num->digits);
+ for (size_t idx = 0; idx < num_size; idx++) {
+ vector_result_t get_res = vector_get(num->digits, idx);
+ if (get_res.status != VECTOR_OK) {
+ vector_destroy(shifted->digits);
+ free(shifted);
+ 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(shifted->digits, digit);
+ if (push_res.status != VECTOR_OK) {
+ vector_destroy(shifted->digits);
+ free(shifted);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ }
+
+ result.value.number = shifted;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integer shifted successfully");
+
+ return result;
+}
+
+/**
+ * bigint_split
+ * @num: a non-null big integers
+ * @m: the pivot/position where to split
+ * @high: digits \in [0, m)
+ * @low: digits \in [m, size)
+ *
+ * Splits number into @high and @low parts at position @m
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_split(const bigint_t *num, size_t m, bigint_t **high, bigint_t **low) {
+ bigint_result_t result = {0};
+
+ const size_t size = vector_size(num->digits);
+
+ // Low part: digits \in [0, m)
+ *low = malloc(sizeof(bigint_t));
+ if (*low == NULL) {
+ result.status = BIGINT_ERR_ALLOCATE;
+ SET_MSG(result, "Failed to allocate memory for big integer");
+
+ return result;
+ }
+
+ vector_result_t low_res = vector_new(m ? m : 1, sizeof(int));
+ if (low_res.status != VECTOR_OK) {
+ free(*low);
+ result.status = BIGINT_ERR_ALLOCATE;
+ COPY_MSG(result, low_res.message);
+
+ return result;
+ }
+
+ (*low)->digits = low_res.value.vector;
+ (*low)->is_negative = false;
+
+ for (size_t idx = 0; idx < m && idx < size; idx++) {
+ vector_result_t get_res = vector_get(num->digits, idx);
+ if (get_res.status != VECTOR_OK) {
+ vector_destroy((*low)->digits);
+ free(*low);
+ 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((*low)->digits, digit);
+ if (push_res.status != VECTOR_OK) {
+ vector_destroy((*low)->digits);
+ free(*low);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ }
+
+ if (vector_size((*low)->digits) == 0) {
+ int zero = 0;
+ vector_result_t push_res = vector_push((*low)->digits, &zero);
+ if (push_res.status != VECTOR_OK) {
+ vector_destroy((*low)->digits);
+ free(*low);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ }
+
+ // First pass of zero trimming
+ bigint_result_t first_trim_res = bigint_trim_zeros(*low);
+ if (first_trim_res.status != BIGINT_OK) {
+ vector_destroy((*low)->digits);
+ free(*low);
+
+ return first_trim_res;
+ }
+
+ // High part: digits \in [m, size)
+ *high = malloc(sizeof(bigint_t));
+ if (*high == NULL) {
+ vector_destroy((*low)->digits);
+ free(*low);
+ result.status = BIGINT_ERR_ALLOCATE;
+ SET_MSG(result, "Failed to allocate memory for big integer");
+
+ return result;
+ }
+
+ vector_result_t high_res = vector_new(size > m ? (size - m) : 1, sizeof(int));
+ if (high_res.status != VECTOR_OK) {
+ vector_destroy((*low)->digits);
+ free(*low);
+ free(*high);
+
+ result.status = BIGINT_ERR_ALLOCATE;
+ COPY_MSG(result, low_res.message);
+
+ return result;
+ }
+
+ (*high)->digits = high_res.value.vector;
+ (*high)->is_negative = false;
+
+ if (size > m) {
+ for (size_t idx = m; idx < size; idx++) {
+ vector_result_t get_res = vector_get(num->digits, idx);
+ if (get_res.status != VECTOR_OK) {
+ vector_destroy((*low)->digits);
+ vector_destroy((*high)->digits);
+ free(*low);
+ free(*high);
+
+ 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((*high)->digits, digit);
+ if (push_res.status != VECTOR_OK) {
+ vector_destroy((*low)->digits);
+ vector_destroy((*high)->digits);
+ free(*low);
+ free(*high);
+
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ }
+ } else {
+ int zero = 0;
+ vector_result_t push_res = vector_push((*high)->digits, &zero);
+ if (push_res.status != VECTOR_OK) {
+ vector_destroy((*low)->digits);
+ vector_destroy((*high)->digits);
+ free(*low);
+ free(*high);
+
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ }
+
+ // Second pass of zero trimming
+ bigint_result_t second_trim_res = bigint_trim_zeros(*high);
+ if (second_trim_res.status != BIGINT_OK) {
+ vector_destroy((*low)->digits);
+ vector_destroy((*high)->digits);
+ free(*low);
+ free(*high);
+
+ return second_trim_res;
+ }
+
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big number successfully splitted");
+
+ return result;
+}
+
+/**
+ * bigint_karatsuba_base
+ * @x: a non-null big integer
+ * @y: a non-null big integer
+ *
+ * Base case of the Karatsuba recursive algorithm
+ * which uses a "grade school" multiplication.
+ * Its complexity is O(n^2)
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_karatsuba_base(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+
+ bigint_result_t prod_res = bigint_from_int(0);
+ if (prod_res.status != BIGINT_OK) {
+ result.status = BIGINT_ERR_ALLOCATE;
+ COPY_MSG(result, prod_res.message);
+
+ return result;
+ }
+
+ bigint_t *product = prod_res.value.number;
+ const size_t x_size = vector_size(x->digits);
+ const size_t y_size = vector_size(y->digits);
+
+ for (size_t i = 0; i < x_size; i++) {
+ long long carry = 0;
+
+ vector_result_t get_res = vector_get(x->digits, i);
+ if (get_res.status != VECTOR_OK) {
+ bigint_destroy(product);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, get_res.message);
+
+ return result;
+ }
+
+ int *x_digit = (int*)get_res.value.element;
+ for (size_t j = 0; j < y_size || carry; j++) {
+ int *y_digit = NULL;
+ int *curr = NULL;
+
+ if (j < y_size) {
+ vector_result_t y_res = vector_get(y->digits, j);
+ if (y_res.status != VECTOR_OK) {
+ bigint_destroy(product);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, y_res.message);
+
+ return result;
+ }
+
+ y_digit = (int*)y_res.value.element;
+ }
+
+ if ((i + j) < vector_size(product->digits)) {
+ vector_result_t curr_res = vector_get(product->digits, i + j);
+ if (curr_res.status != VECTOR_OK) {
+ bigint_destroy(product);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, curr_res.message);
+
+ return result;
+ }
+
+ curr = (int*)curr_res.value.element;
+ }
+
+ long long partial_prod = carry;
+ if (curr) { partial_prod += *curr; }
+ if (y_digit) { partial_prod += (long long)(*x_digit) * (*y_digit); }
+
+ int new_digit =(int)(partial_prod % BIGINT_BASE);
+ carry = partial_prod / BIGINT_BASE;
+
+ if (curr) {
+ vector_result_t set_res = vector_set(product->digits, i + j, &new_digit);
+ if (set_res.status != VECTOR_OK) {
+ bigint_destroy(product);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, set_res.message);
+
+ return result;
+ }
+ } else {
+ vector_result_t push_res = vector_push(product->digits, &new_digit);
+ if (push_res.status != VECTOR_OK) {
+ bigint_destroy(product);
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ return result;
+ }
+ }
+ }
+ }
+
+ bigint_result_t trim_res = bigint_trim_zeros(product);
+ if (trim_res.status != BIGINT_OK) {
+ bigint_destroy(product);
+
+ return trim_res;
+ }
+
+ result.value.number = product;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Product between big integers was successful");
+
+ return result;
+}
+
+/**
+ * bigint_karatusba
+ * @x: a non-null big integer
+ * @y: a non-null big integer
+ *
+ * Perform a multiplication using Karatsuba recursive algorithm
+ * in O(n^{\log_2 3}) \approx O(n^{1.585})
+ */
+bigint_result_t bigint_karatsuba(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+ bigint_result_t tmp_res = {0};
+
+ if (x == NULL || y == NULL) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid big integers");
+
+ return result;
+ }
+
+ const size_t x_size = vector_size(x->digits);
+ const size_t y_size = vector_size(y->digits);
+
+ // Base case using "grade school" quadratic algorithm
+ if (x_size <= 32 || y_size <= 32) {
+ return bigint_karatsuba_base(x, 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;
+
+ // Results of each step
+ bigint_t *x1 = NULL, *x0 = NULL;
+ 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;
+
+ // 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
+ tmp_res = bigint_split(y, pivot, &y1, &y0);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+
+ // Perform karatsuba's trick
+ 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;
+
+ 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
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ tmp_res = bigint_add(z2_shifted, z1_shifted);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+ temp = tmp_res.value.number;
+
+ tmp_res = bigint_add(temp, z0);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+ product = tmp_res.value.number;
+
+ // Destroy intermediate allocations except for the product
+ 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);
+
+ result.value.number = product;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Product between big integers was successful");
+
+cleanup: // Destroy intermediate allocations on error
+ if (x1) { bigint_destroy(x1); }
+ if (x0) { bigint_destroy(x0); }
+ if (y1) { bigint_destroy(y1); }
+ if (y0) { bigint_destroy(y0); }
+ if (z0) { bigint_destroy(z0); }
+ if (z2) { bigint_destroy(z2); }
+ if (x_sum) { bigint_destroy(x_sum); }
+ if (y_sum) { bigint_destroy(y_sum); }
+ if (z1_temp) { bigint_destroy(z1_temp); }
+ if (z1_sub1) { bigint_destroy(z1_sub1); }
+ if (z1) { bigint_destroy(z1); }
+ if (z2_shifted) { bigint_destroy(z2_shifted); }
+ if (z1_shifted) { bigint_destroy(z1_shifted); }
+ if (temp) { bigint_destroy(temp); }
+ if (product) { bigint_destroy(product); }
+
+ return result;
+}
+
+/**
+ * bigint_dev
+ * @x: a valid non-null big integer (dividend)
+ * @y: a valid non-null big integer (divisor)
+ *
+ * Computes division using long division algorithm in O(n^2)
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_div(const bigint_t *x, const bigint_t *y) {
+ bigint_result_t result = {0};
+ bigint_result_t tmp_res = {0};
+
+ bigint_t *quotient = NULL;
+ bigint_t *remainder = NULL;
+ bigint_t *abs_y = NULL;
+
+ if (x == NULL || y == NULL) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid big numbers");
+
+ return result;
+ }
+
+ // Check for division by zero
+ const size_t y_size = vector_size(y->digits);
+ if (y_size == 0) {
+ result.status = BIGINT_ERR_DIV_BY_ZERO;
+ SET_MSG(result, "Cannot divide by zero");
+
+ return result;
+ }
+
+ if (y_size == 1) {
+ vector_result_t y_val_res = vector_get(y->digits, 0);
+ if (y_val_res.status != VECTOR_OK) {
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, y_val_res.message);
+
+ return result;
+ }
+
+ int *y_val = (int*)y_val_res.value.element;
+ if (*y_val == 0) {
+ result.status = BIGINT_ERR_DIV_BY_ZERO;
+ SET_MSG(result, "Cannot divide by zero");
+
+ return result;
+ }
+ }
+
+ // If |x| < |y| then result is zero
+ tmp_res = bigint_compare_abs(x, y);
+ if (tmp_res.status != BIGINT_OK) { return tmp_res; }
+
+ if (tmp_res.value.compare_status < 0) {
+ tmp_res = bigint_from_int(0);
+ if (tmp_res.status != BIGINT_OK) { return tmp_res; }
+
+ result.value.number = tmp_res.value.number;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Division between big integers was successful");
+
+ return result;
+ }
+
+ // Initialize quotient and remainder
+ tmp_res = bigint_from_int(0);
+ if (tmp_res.status != BIGINT_OK) { return tmp_res; }
+ quotient = tmp_res.value.number;
+
+ tmp_res = bigint_from_int(0);
+ if (tmp_res.status != BIGINT_OK) { bigint_destroy(quotient); return tmp_res; }
+ remainder = tmp_res.value.number;
+
+ // Create absolute value of y for later comparisons
+ tmp_res = bigint_clone(y);
+ if (tmp_res.status != BIGINT_OK) {
+ bigint_destroy(quotient);
+ bigint_destroy(remainder);
+
+ return tmp_res;
+ }
+
+ abs_y = tmp_res.value.number;
+ abs_y->is_negative = false;
+
+ // Long division algorithm applied from MSB to LSB
+ const size_t x_size = vector_size(x->digits);
+ for (int idx = (int)x_size - 1; idx >= 0; idx--) {
+ // Shift remainder left by one base digit (multiplication by BASE)
+ tmp_res = bigint_shift_left(remainder, 1);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+
+ bigint_t *shifted_remainder = tmp_res.value.number;
+ bigint_destroy(remainder);
+ remainder = shifted_remainder;
+
+ // Add current digit of 'x' to the least significant position of remainder
+ vector_result_t digit_res = vector_get(x->digits, idx);
+ if (digit_res.status != VECTOR_OK) {
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, digit_res.message);
+
+ goto cleanup;
+ }
+
+ int *x_digit = (int*)digit_res.value.element;
+
+ vector_result_t set_res = vector_set(remainder->digits, 0, x_digit);
+ if (set_res.status != VECTOR_OK) {
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, set_res.message);
+
+ goto cleanup;
+ }
+
+ tmp_res = bigint_trim_zeros(remainder);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+
+ // COunt how many times 'y' fits into current remainder
+ size_t count = 0;
+ while (1) {
+ tmp_res = bigint_compare_abs(remainder, abs_y);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+ if (tmp_res.value.compare_status < 0) { break; } // remainder < abs_y
+
+ // remainder = remainder - abs_y
+ tmp_res = bigint_sub_abs(remainder, abs_y);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+
+ bigint_t *new_remainder = tmp_res.value.number;
+ bigint_destroy(remainder);
+ remainder = new_remainder;
+ count++;
+ }
+
+ // Add count to quotient digits
+ vector_result_t push_res = vector_push(quotient->digits, &count);
+ if (push_res.status != VECTOR_OK) {
+ result.status = BIGINT_ERR_INVALID;
+ COPY_MSG(result, push_res.message);
+
+ goto cleanup;
+ }
+ }
+
+ // Reverse quotient digits
+ const size_t q_size = vector_size(quotient->digits);
+ for (size_t idx = 0; idx < q_size / 2; idx++) {
+ vector_result_t left_res = vector_get(quotient->digits, idx);
+ vector_result_t right_res = vector_get(quotient->digits, q_size - 1 - idx);
+
+ if (left_res.status != VECTOR_OK || right_res.status != VECTOR_OK) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Failed to access vector elements");
+
+ goto cleanup;
+ }
+
+ int *left = (int*)left_res.value.element;
+ int *right = (int*)right_res.value.element;
+ int temp = *left;
+
+ vector_set(quotient->digits, idx, right);
+ vector_set(quotient->digits, q_size - 1 - idx, &temp);
+ }
+
+ quotient->is_negative = (x->is_negative != y->is_negative);
+
+ tmp_res = bigint_trim_zeros(quotient);
+ if (tmp_res.status != BIGINT_OK) { result = tmp_res; goto cleanup; }
+
+ bigint_destroy(remainder);
+ bigint_destroy(abs_y);
+
+ result.value.number = quotient;
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Division between big integers was successful");
+
+ return result;
+
+cleanup:
+ if (quotient) { bigint_destroy(quotient); }
+ if (remainder) { bigint_destroy(remainder); }
+ if (abs_y) { bigint_destroy(abs_y); }
+
+ return result;
+}
+
+/**
+ * bigint_destroy
+ * @number: a valid non-null 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 = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid big integer");
+
+ return result;
+ }
+
+ vector_destroy(number->digits);
+ free(number);
+
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Big integer successfully deleted");
+
+ return result;
+}
+
+/**
+ * bigint_printf
+ * @format: format string
+ * @...: variadic arguments
+ *
+ * Prints a bigint integer to stdout using the custom '%B' placeholder
+ *
+ * Returns a bigint_result_t data type
+ */
+bigint_result_t bigint_printf(const char *format, ...) {
+ bigint_result_t result = {0};
+
+ if (format == NULL) {
+ result.status = BIGINT_ERR_INVALID;
+ SET_MSG(result, "Invalid format string");
+
+ return result;
+ }
+
+ va_list args;
+ va_start(args, format);
+
+ // Process string char by char
+ for (const char *p = format; *p != '\0'; p++) {
+ if (*p == '%' && *(p + 1) == 'B') {
+ // Process a big number
+ bigint_t *num = va_arg(args, bigint_t*);
+ if (num == NULL) {
+ printf("");
+ } else {
+ bigint_result_t num_str_res = bigint_to_string(num);
+ if (num_str_res.status != BIGINT_OK) {
+ va_end(args);
+ return num_str_res;
+ }
+
+ char* const number_str = num_str_res.value.string_num;
+ printf("%s", number_str);
+ free(number_str);
+ }
+ p++;
+ } else if (*p == '%' && *(p + 1) != '%') {
+ // Handle common printf placeholders
+ p++;
+ char placeholder = *p;
+
+ switch (placeholder) {
+ case 'd':
+ case 'i': {
+ int val = va_arg(args, int);
+ printf("%d", val);
+
+ break;
+ }
+ case 'u': {
+ unsigned int val = va_arg(args, unsigned int);
+ printf("%u", val);
+
+ break;
+ }
+ case 'l': {
+ if (*(p + 1) == 'd' || *(p + 1) == 'i') {
+ long val = va_arg(args, long);
+ printf("%ld", val);
+ p++;
+ } else if (*(p + 1) == 'l' && (*(p + 2) == 'd' || *(p + 2) == 'i')) {
+ long long val = va_arg(args, long long);
+ printf("%lld", val);
+ p += 2;
+ } else if (*(p + 1) == 'u') {
+ unsigned long val = va_arg(args, unsigned long);
+ printf("%lu", val);
+ p++;
+ }
+ break;
+ }
+ case 's': {
+ char *val = va_arg(args, char*);
+ printf("%s", val ? val : "");
+ break;
+ }
+ case 'c': {
+ int val = va_arg(args, int);
+ printf("%c", val);
+ break;
+ }
+ case 'f': {
+ double val = va_arg(args, double);
+ printf("%f", val);
+ break;
+ }
+ case 'p': {
+ void *val = va_arg(args, void*);
+ printf("%p", val);
+ break;
+ }
+ case 'x': {
+ unsigned int val = va_arg(args, unsigned int);
+ printf("%x", val);
+ break;
+ }
+ case 'X': {
+ unsigned int val = va_arg(args, unsigned int);
+ printf("%X", val);
+ break;
+ }
+ default: // Unsupported placeholder so we just print it
+ printf("%%%c", placeholder);
+ break;
+ }
+ } else if (*p == '%' && *(p + 1) == '%') {
+ // print the percent character as is
+ putchar('%');
+ p++;
+ } else { // Print ASCII character
+ putchar(*p);
+ }
+ }
+
+ va_end(args);
+
+ result.status = BIGINT_OK;
+ SET_MSG(result, "Printf completed successfully");
+
+ return result;
+}
diff --git a/src/bigint.h b/src/bigint.h
new file mode 100644
index 0000000..40b9c34
--- /dev/null
+++ b/src/bigint.h
@@ -0,0 +1,64 @@
+#ifndef BIGINT_H
+#define BIGINT_H
+
+#define RESULT_MSG_SIZE 64
+
+// 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
+#include "vector.h"
+
+typedef enum {
+ BIGINT_OK = 0x0,
+ BIGINT_ERR_ALLOCATE,
+ BIGINT_ERR_DIV_BY_ZERO,
+ BIGINT_ERR_INVALID
+} bigint_status_t;
+
+typedef struct {
+ vector_t *digits;
+ bool is_negative;
+} bigint_t;
+
+typedef struct {
+ bigint_t *quotient;
+ bigint_t *remainder;
+} div_result_t;
+
+typedef struct {
+ bigint_status_t status;
+ uint8_t message[RESULT_MSG_SIZE];
+ union {
+ bigint_t *number;
+ div_result_t division;
+ int8_t compare_status;
+ 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_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_divmod(const bigint_t *x, const bigint_t *y);
+bigint_result_t bigint_mod(const bigint_t *x, const bigint_t *y);
+bigint_result_t bigint_destroy(bigint_t *number);
+bigint_result_t bigint_printf(const char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/map.c b/src/map.c
index d752697..542065c 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
@@ -35,7 +37,7 @@ uint64_t hash_key(const char *key) {
*
* Returns a map_result_t data type containing a new hash map
*/
-map_result_t map_new() {
+map_result_t map_new(void) {
map_result_t result = {0};
map_t *map = malloc(sizeof(map_t));
diff --git a/src/map.h b/src/map.h
index 704b820..a7f3643 100644
--- a/src/map.h
+++ b/src/map.h
@@ -53,7 +53,7 @@ typedef struct {
extern "C" {
#endif
-map_result_t map_new();
+map_result_t map_new(void);
map_result_t map_add(map_t *map, const char *key, void *value);
map_result_t map_get(const map_t *map, const char *key);
map_result_t map_remove(map_t *map, const char *key);
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/tests/test_bigint.c b/tests/test_bigint.c
new file mode 100644
index 0000000..0cc5aad
--- /dev/null
+++ b/tests/test_bigint.c
@@ -0,0 +1,381 @@
+/*
+ * Unit tests for BigInt data type
+*/
+
+#define TEST(NAME) do { \
+ printf("Running test_%s...", #NAME); \
+ test_##NAME(); \
+ printf(" PASSED\n"); \
+} while(0)
+
+#include
+#include
+#include
+#include
+
+#include "../src/bigint.h"
+
+static void bigint_eq(const bigint_t *number, const char *expected) {
+ bigint_result_t exp_num_res = bigint_from_string(expected);
+ assert(exp_num_res.status == BIGINT_OK);
+ bigint_t *exp_num = exp_num_res.value.number;
+
+ bigint_result_t cmp_res = bigint_compare(number, exp_num);
+ assert(cmp_res.status == BIGINT_OK);
+
+ const int8_t cmp = cmp_res.value.compare_status;
+ assert(cmp == 0);
+
+ bigint_destroy(exp_num);
+}
+
+// Test creating big integers from int
+void test_bigint_from_int(void) {
+ bigint_result_t res = bigint_from_int(0);
+
+ assert(res.status == BIGINT_OK);
+ bigint_eq(res.value.number, "0");
+ bigint_destroy(res.value.number);
+
+ res = bigint_from_int(10);
+ assert(res.status == BIGINT_OK);
+ bigint_eq(res.value.number, "10");
+ bigint_destroy(res.value.number);
+
+ res = bigint_from_int(-12345678900LL);
+ assert(res.status == BIGINT_OK);
+ bigint_eq(res.value.number, "-12345678900");
+ bigint_destroy(res.value.number);
+}
+
+// Test creating big integers from string
+void test_bigint_from_string(void) {
+ bigint_result_t res = bigint_from_string("00000123");
+
+ assert(res.status == BIGINT_OK);
+ bigint_eq(res.value.number, "123");
+ bigint_destroy(res.value.number);
+
+ res = bigint_from_string("-00000456789");
+ assert(res.status == BIGINT_OK);
+ bigint_eq(res.value.number, "-456789");
+ bigint_destroy(res.value.number);
+}
+
+// Test sum between big integers
+void test_bigint_add(void) {
+ bigint_result_t x = bigint_from_int(123);
+ bigint_result_t y = bigint_from_int(456);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t sum = bigint_add(x.value.number, y.value.number);
+ assert(sum.status == BIGINT_OK);
+ bigint_eq(sum.value.number, "579");
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+ bigint_destroy(sum.value.number);
+}
+
+// Test difference between big numbers
+void test_bigint_sub(void) {
+ bigint_result_t x = bigint_from_int(456);
+ bigint_result_t y = bigint_from_int(123);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t diff = bigint_sub(x.value.number, y.value.number);
+ assert(diff.status == BIGINT_OK);
+ bigint_eq(diff.value.number, "333");
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+ bigint_destroy(diff.value.number);
+}
+
+// Test difference between big numbers with negative result
+void test_bigint_sub_neg(void) {
+ bigint_result_t x = bigint_from_int(123);
+ bigint_result_t y = bigint_from_int(456);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t diff = bigint_sub(x.value.number, y.value.number);
+ assert(diff.status == BIGINT_OK);
+ bigint_eq(diff.value.number, "-333");
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+ bigint_destroy(diff.value.number);
+}
+
+// Test difference between mixed big numbers
+void test_bigint_sub_mixed(void) {
+ bigint_result_t x = bigint_from_int(456);
+ bigint_result_t y = bigint_from_int(-123);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t diff = bigint_sub(x.value.number, y.value.number);
+ assert(diff.status == BIGINT_OK);
+ bigint_eq(diff.value.number, "579");
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+ bigint_destroy(diff.value.number);
+}
+
+// Test product between big numbers
+void test_bigint_prod(void) {
+ bigint_result_t x = bigint_from_int(1234);
+ bigint_result_t y = bigint_from_int(56789);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t prod = bigint_prod(x.value.number, y.value.number);
+ assert(prod.status == BIGINT_OK);
+ bigint_eq(prod.value.number, "70077626");
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+ bigint_destroy(prod.value.number);
+}
+
+// Test product between mixed negative big numbers
+void test_bigint_prod_mixed(void) {
+ bigint_result_t x = bigint_from_int(-1234);
+ bigint_result_t y = bigint_from_int(56789);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t prod = bigint_prod(x.value.number, y.value.number);
+ assert(prod.status == BIGINT_OK);
+ bigint_eq(prod.value.number, "-70077626");
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+ bigint_destroy(prod.value.number);
+}
+
+// Test product between negative big numbers
+void test_bigint_prod_neg(void) {
+ bigint_result_t x = bigint_from_int(-1234);
+ bigint_result_t y = bigint_from_int(-56789);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t prod = bigint_prod(x.value.number, y.value.number);
+ assert(prod.status == BIGINT_OK);
+ bigint_eq(prod.value.number, "70077626");
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+ bigint_destroy(prod.value.number);
+}
+
+// Test division between big numbers
+void test_bigint_div(void) {
+ bigint_result_t x = bigint_from_int(100);
+ bigint_result_t y = bigint_from_int(2);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t div = bigint_divmod(x.value.number, y.value.number);
+ assert(div.status == BIGINT_OK);
+
+ bigint_t* const quotient = div.value.division.quotient;
+ bigint_t* const remainder = div.value.division.remainder;
+
+ bigint_eq(quotient, "50");
+ bigint_eq(remainder, "0");
+
+ bigint_destroy(quotient);
+ bigint_destroy(remainder);
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+}
+
+// Test division between big numbers with negative dividend
+// This library follows C-style divison such that sign(remainder) = sign(dividend)
+void test_bigint_div_dividend(void) {
+ bigint_result_t x = bigint_from_int(-100);
+ bigint_result_t y = bigint_from_int(3);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t div = bigint_divmod(x.value.number, y.value.number);
+ assert(div.status == BIGINT_OK);
+
+ bigint_t* const quotient = div.value.division.quotient;
+ bigint_t* const remainder = div.value.division.remainder;
+
+ bigint_eq(quotient, "-33");
+ bigint_eq(remainder, "-1");
+
+ bigint_destroy(quotient);
+ bigint_destroy(remainder);
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+}
+
+// Test division between big numbers with negative divisor
+// This library follows C-style divison such that sign(remainder) = sign(dividend)
+void test_bigint_div_divisor(void) {
+ bigint_result_t x = bigint_from_int(13);
+ bigint_result_t y = bigint_from_int(-4);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t div = bigint_divmod(x.value.number, y.value.number);
+ assert(div.status == BIGINT_OK);
+
+ bigint_t* const quotient = div.value.division.quotient;
+ bigint_t* const remainder = div.value.division.remainder;
+
+ bigint_eq(quotient, "-3");
+ bigint_eq(remainder, "1");
+
+ bigint_destroy(quotient);
+ bigint_destroy(remainder);
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+}
+
+// Test division between big numbers with negative numbers
+// This library follows C-style divison such that sign(remainder) = sign(dividend)
+void test_bigint_div_neg(void) {
+ bigint_result_t x = bigint_from_int(-100);
+ bigint_result_t y = bigint_from_int(-3);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t div = bigint_divmod(x.value.number, y.value.number);
+ assert(div.status == BIGINT_OK);
+
+ bigint_t* const quotient = div.value.division.quotient;
+ bigint_t* const remainder = div.value.division.remainder;
+
+ bigint_eq(quotient, "33");
+ bigint_eq(remainder, "-1");
+
+ bigint_destroy(quotient);
+ bigint_destroy(remainder);
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+}
+
+// Test division by zero
+void test_bigint_div_by_zero(void) {
+ bigint_result_t x = bigint_from_int(-100);
+ bigint_result_t y = bigint_from_int(0);
+
+ assert(x.status == BIGINT_OK && y.status == BIGINT_OK);
+
+ bigint_result_t div = bigint_divmod(x.value.number, y.value.number);
+ assert(div.status == BIGINT_ERR_DIV_BY_ZERO);
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+}
+
+// Test cloning of big numbers
+void test_bigint_clone(void) {
+ bigint_result_t x = bigint_from_string("0010101010");
+
+ assert(x.status == BIGINT_OK);
+
+ bigint_result_t cloned = bigint_clone(x.value.number);
+ assert(cloned.status == BIGINT_OK);
+
+ bigint_eq(cloned.value.number, "10101010");
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(cloned.value.number);
+}
+
+// Test comparison between equal numbers
+void test_bigint_compare_eq(void) {
+ bigint_result_t x = bigint_from_int(123);
+ bigint_result_t y = bigint_from_int(123);
+
+ assert(x.status == BIGINT_OK);
+ assert(y.status == BIGINT_OK);
+
+ bigint_result_t cmp_res = bigint_compare(x.value.number, y.value.number);
+ assert(cmp_res.status == BIGINT_OK);
+
+ const int8_t cmp = cmp_res.value.compare_status;
+ assert(cmp == 0);
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+}
+
+// Test comparison between numbers (less than)
+void test_bigint_compare_lt(void) {
+ bigint_result_t x = bigint_from_int(-123);
+ bigint_result_t y = bigint_from_int(0);
+
+ assert(x.status == BIGINT_OK);
+ assert(y.status == BIGINT_OK);
+
+ bigint_result_t cmp_res = bigint_compare(x.value.number, y.value.number);
+ assert(cmp_res.status == BIGINT_OK);
+
+ const int8_t cmp = cmp_res.value.compare_status;
+ assert(cmp == -1);
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+}
+
+// Test comparison between numbers (greater than)
+void test_bigint_compare_gt(void) {
+ bigint_result_t x = bigint_from_int(123);
+ bigint_result_t y = bigint_from_int(-5);
+
+ assert(x.status == BIGINT_OK);
+ assert(y.status == BIGINT_OK);
+
+ bigint_result_t cmp_res = bigint_compare(x.value.number, y.value.number);
+ assert(cmp_res.status == BIGINT_OK);
+
+ const int8_t cmp = cmp_res.value.compare_status;
+ assert(cmp == 1);
+
+ bigint_destroy(x.value.number);
+ bigint_destroy(y.value.number);
+}
+
+
+int main(void) {
+ printf("=== Running BigInt unit tests ===\n\n");
+
+ TEST(bigint_from_int);
+ TEST(bigint_from_string);
+ TEST(bigint_add);
+ TEST(bigint_sub);
+ TEST(bigint_sub_neg);
+ TEST(bigint_sub_mixed);
+ TEST(bigint_prod);
+ TEST(bigint_prod_mixed);
+ TEST(bigint_prod_neg);
+ TEST(bigint_div);
+ TEST(bigint_div_dividend);
+ TEST(bigint_div_divisor);
+ TEST(bigint_div_neg);
+ TEST(bigint_div_by_zero);
+ TEST(bigint_clone);
+ TEST(bigint_compare_eq);
+ TEST(bigint_compare_lt);
+ TEST(bigint_compare_gt);
+
+ printf("\n=== All tests passed ===\n");
+
+ return 0;
+}
diff --git a/tests/test_map.c b/tests/test_map.c
index 3a936f5..47085b9 100644
--- a/tests/test_map.c
+++ b/tests/test_map.c
@@ -15,7 +15,7 @@
#include "../src/map.h"
// Create a new map
-void test_map_new() {
+void test_map_new(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -27,7 +27,7 @@ void test_map_new() {
}
// Add elements to map
-void test_map_add() {
+void test_map_add(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -47,7 +47,7 @@ void test_map_add() {
}
// Add multiple elements to the map
-void test_map_add_multiple() {
+void test_map_add_multiple(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -68,7 +68,7 @@ void test_map_add_multiple() {
}
// Get map element
-void test_map_get() {
+void test_map_get(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -85,7 +85,7 @@ void test_map_get() {
}
// Get non-existing key from map
-void test_map_get_invalid() {
+void test_map_get_invalid(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -98,7 +98,7 @@ void test_map_get_invalid() {
}
// Map with heterogeneous types
-void test_map_mixed() {
+void test_map_mixed(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -126,7 +126,7 @@ void test_map_mixed() {
}
// Update existing map key
-void test_map_update() {
+void test_map_update(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -149,7 +149,7 @@ void test_map_update() {
}
// Remove an element from map
-void test_map_remove() {
+void test_map_remove(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -177,7 +177,7 @@ void test_map_remove() {
}
// Remove non-existing key from map
-void test_map_remove_invalid() {
+void test_map_remove_invalid(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -190,7 +190,7 @@ void test_map_remove_invalid() {
}
// Clear the map
-void test_map_clear() {
+void test_map_clear(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -212,7 +212,7 @@ void test_map_clear() {
}
// Clear empty map
-void test_map_clear_empty() {
+void test_map_clear_empty(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -226,7 +226,7 @@ void test_map_clear_empty() {
}
// Multiple operations in sequence (add, update, delete and clear)
-void test_map_sequence() {
+void test_map_sequence(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -266,7 +266,7 @@ typedef struct {
short age;
} Person;
-void test_map_struct() {
+void test_map_struct(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
@@ -298,7 +298,7 @@ void test_map_struct() {
}
// Test map capacity tracking
-void test_map_cap() {
+void test_map_cap(void) {
map_result_t res = map_new();
assert(res.status == MAP_OK);
diff --git a/tests/test_vector b/tests/test_vector
deleted file mode 100755
index c9066fd..0000000
Binary files a/tests/test_vector and /dev/null differ
diff --git a/tests/test_vector.c b/tests/test_vector.c
index fd1ca59..52fdcac 100644
--- a/tests/test_vector.c
+++ b/tests/test_vector.c
@@ -15,7 +15,7 @@
#include "../src/vector.h"
// Create a new vector
-void test_vector_new() {
+void test_vector_new(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -27,14 +27,14 @@ void test_vector_new() {
}
// Create a vector with zero capacity
-void test_vector_new_zcap() {
+void test_vector_new_zcap(void) {
vector_result_t res = vector_new(0, sizeof(int));
assert(res.status == VECTOR_ERR_ALLOCATE);
}
// Push elements to vector
-void test_vector_push() {
+void test_vector_push(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -54,7 +54,7 @@ void test_vector_push() {
}
// Trigger vector reallocation
-void test_vector_push_realloc() {
+void test_vector_push_realloc(void) {
vector_result_t res = vector_new(1, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -72,7 +72,7 @@ void test_vector_push_realloc() {
}
// Get vector elements
-void test_vector_get() {
+void test_vector_get(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -89,7 +89,7 @@ void test_vector_get() {
}
// Test out of bounds
-void test_vector_get_ofb() {
+void test_vector_get_ofb(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -119,7 +119,7 @@ vector_order_t cmp_int_desc(const void *x, const void *y) {
return cmp_int_asc(y, x);
}
-void test_vector_sort_int_asc() {
+void test_vector_sort_int_asc(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -134,7 +134,9 @@ void test_vector_sort_int_asc() {
assert(sort_res.status == VECTOR_OK);
const int expected[] = { -7, 1, 4, 6, 12, 25, 25, 71 };
- for (size_t idx = 0; idx < vector_size(v); idx++) {
+
+ const size_t sz = vector_size(v);
+ for (size_t idx = 0; idx < sz; idx++) {
int *val = (int*)vector_get(v, idx).value.element;
assert(*val == expected[idx]);
}
@@ -142,7 +144,7 @@ void test_vector_sort_int_asc() {
vector_destroy(v);
}
-void test_vector_sort_int_desc() {
+void test_vector_sort_int_desc(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -157,7 +159,9 @@ void test_vector_sort_int_desc() {
assert(sort_res.status == VECTOR_OK);
const int expected[] = { 71, 25, 25, 12, 6, 4, 1, -7 };
- for (size_t idx = 0; idx < vector_size(v); idx++) {
+
+ const size_t sz = vector_size(v);
+ for (size_t idx = 0; idx < sz; idx++) {
int *val = (int*)vector_get(v, idx).value.element;
assert(*val == expected[idx]);
}
@@ -183,7 +187,7 @@ vector_order_t cmp_string_desc(const void *x, const void *y) {
return VECTOR_ORDER_EQ;
}
-void test_vector_sort_string() {
+void test_vector_sort_string(void) {
vector_result_t res = vector_new(5, sizeof(char*));
assert(res.status == VECTOR_OK);
@@ -198,7 +202,9 @@ void test_vector_sort_string() {
assert(sort_res.status == VECTOR_OK);
const char *expected[] = { "world!", "system-programming", "hello", "foo", "embedded", "bar"};
- for (size_t idx = 0; idx < vector_size(v); idx++) {
+
+ const size_t sz = vector_size(v);
+ for (size_t idx = 0; idx < sz; idx++) {
const char *val = *(const char**)vector_get(v, idx).value.element;
assert(!strcmp(val, expected[idx]));
}
@@ -234,7 +240,7 @@ vector_order_t cmp_person_by_name(const void *x, const void *y) {
return VECTOR_ORDER_EQ;
}
-void test_vector_sort_struct_by_age() {
+void test_vector_sort_struct_by_age(void) {
vector_result_t res = vector_new(5, sizeof(Person));
assert(res.status == VECTOR_OK);
@@ -257,7 +263,8 @@ void test_vector_sort_struct_by_age() {
{ .name = "Bob", .age = 45 }
};
- for (size_t idx = 0; idx < vector_size(people); idx++) {
+ const size_t sz = sizeof(expected) / sizeof(expected[0]);
+ for (size_t idx = 0; idx < sz; idx++) {
Person *p = (Person*)vector_get(people, idx).value.element;
assert(!strcmp(p->name, expected[idx].name));
assert(p->age == expected[idx].age);
@@ -266,7 +273,7 @@ void test_vector_sort_struct_by_age() {
vector_destroy(people);
}
-void test_vector_sort_struct_by_name() {
+void test_vector_sort_struct_by_name(void) {
vector_result_t res = vector_new(5, sizeof(Person));
assert(res.status == VECTOR_OK);
@@ -295,7 +302,8 @@ void test_vector_sort_struct_by_name() {
{ .name = "Sophia", .age = 45 }
};
- for (size_t idx = 0; idx < vector_size(people); idx++) {
+ const size_t sz = vector_size(people);
+ for (size_t idx = 0; idx < sz; idx++) {
Person *p = (Person*)vector_get(people, idx).value.element;
assert(!strcmp(p->name, expected[idx].name));
assert(p->age == expected[idx].age);
@@ -305,7 +313,7 @@ void test_vector_sort_struct_by_name() {
}
// Set vector element
-void test_vector_set() {
+void test_vector_set(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -324,7 +332,7 @@ void test_vector_set() {
}
// Set vector element out of bounds
-void test_vector_set_ofb() {
+void test_vector_set_ofb(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -340,7 +348,7 @@ void test_vector_set_ofb() {
}
// Pop element from vector
-void test_vector_pop() {
+void test_vector_pop(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -361,7 +369,7 @@ void test_vector_pop() {
}
// Test pop element from empty vector
-void test_vector_pop_empty() {
+void test_vector_pop_empty(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -374,7 +382,7 @@ void test_vector_pop_empty() {
}
// Clear vector
-void test_vector_clear() {
+void test_vector_clear(void) {
vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -396,7 +404,7 @@ void test_vector_clear() {
}
// Multiple operations in sequence (push, set, pop and clear)
-void test_vector_sequence() {
+void test_vector_sequence(void) {
vector_result_t res = vector_new(2, sizeof(int));
assert(res.status == VECTOR_OK);
@@ -426,7 +434,7 @@ void test_vector_sequence() {
}
// Vector with chars
-void test_vector_char() {
+void test_vector_char(void) {
vector_result_t res = vector_new(5, sizeof(char));
assert(res.status == VECTOR_OK);
@@ -449,7 +457,7 @@ typedef struct {
int y;
} Point;
-void test_vector_struct() {
+void test_vector_struct(void) {
vector_result_t res = vector_new(5, sizeof(Point));
assert(res.status == VECTOR_OK);
diff --git a/usage.c b/usage.c
index c0f561c..4db9d0a 100644
--- a/usage.c
+++ b/usage.c
@@ -20,10 +20,14 @@
#include "src/vector.h"
#include "src/map.h"
+#include "src/bigint.h"
+
+static int vector_usage(void);
+static int map_usage(void);
+static int bigint_usage(void);
-static int vector_usage();
-static int map_usage();
static vector_order_t cmp_int_asc(const void *x, const void *y);
+static vector_order_t cmp_int_desc(const void *x, const void *y);
int main(void) {
int st;
@@ -36,6 +40,11 @@ int main(void) {
st = map_usage();
if (st) { return st; }
+ SEP(50);
+
+ st = bigint_usage();
+ if (st) { return st; }
+
return 0;
}
@@ -53,7 +62,7 @@ vector_order_t cmp_int_desc(const void *x, const void *y) {
return cmp_int_asc(y, x);
}
-int vector_usage() {
+int vector_usage(void) {
// Create a vector of 3 integers
vector_result_t res = vector_new(3, sizeof(int));
if (res.status != VECTOR_OK) {
@@ -79,7 +88,8 @@ int vector_usage() {
printf("Vector capacity (should be > 5): %zu\n\n", vector_capacity(vector));
// Print the whole vector
- for (size_t idx = 0; idx < vector_size(vector); idx++) {
+ size_t sz = vector_size(vector);
+ for (size_t idx = 0; idx < sz; idx++) {
vector_result_t get_res = vector_get(vector, idx);
if (get_res.status != VECTOR_OK) {
printf("Cannot retrieve vec[%zu]: %s\n", idx, get_res.message);
@@ -127,7 +137,9 @@ int vector_usage() {
}
printf("Added new elements. Before sort: ");
- for (size_t idx = 0; idx < vector_size(vector); idx++) {
+
+ sz = vector_size(vector);
+ for (size_t idx = 0; idx < sz; idx++) {
vector_result_t sort_get_res = vector_get(vector, idx);
if (sort_get_res.status != VECTOR_OK) {
printf("Cannot retrieve vec[%zu]: %s\n", idx, sort_get_res.message);
@@ -148,7 +160,7 @@ int vector_usage() {
}
printf("After sort in ascending order: ");
- for (size_t idx = 0; idx < vector_size(vector); idx++) {
+ for (size_t idx = 0; idx < sz; idx++) {
vector_result_t sort_get_res = vector_get(vector, idx);
if (sort_get_res.status != VECTOR_OK) {
printf("Cannot retrieve vec[%zu]: %s\n", idx, sort_get_res.message);
@@ -170,7 +182,7 @@ int vector_usage() {
}
printf("After sort in descending order: ");
- for (size_t idx = 0; idx < vector_size(vector); idx++) {
+ for (size_t idx = 0; idx < sz; idx++) {
vector_result_t sort_get_res = vector_get(vector, idx);
if (sort_get_res.status != VECTOR_OK) {
printf("Cannot retrieve vec[%zu]: %s\n", idx, sort_get_res.message);
@@ -194,7 +206,7 @@ int vector_usage() {
return 0;
}
-int map_usage() {
+int map_usage(void) {
// Create a new map
map_result_t res = map_new();
if (res.status != MAP_OK) {
@@ -225,7 +237,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");
@@ -282,6 +294,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 +306,90 @@ int map_usage() {
return 0;
}
+
+int bigint_usage(void) {
+ // Create two big integers
+ 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
+ bigint_printf("123456789 + 987654321 (should be 1,111,111,110) = %B\n", sum);
+
+ // 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
+ bigint_printf("123456789 - 987654321 (should be -864,197,532) = %B\n", diff);
+
+ // 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
+ bigint_printf("123456789 * 987654321 (should be 121,932,631,112,635,269) = %B\n", prod);
+
+ bigint_t *a = bigint_from_string("457349545684946456456456567567").value.number;
+ bigint_t *b = bigint_from_string("43569678678678678678678432").value.number;
+
+ // Divide two big integers
+ bigint_result_t div_res = bigint_divmod(a, b);
+ if (div_res.status != BIGINT_OK) {
+ printf("Error while dividing two big numbers: %s\n", div_res.message);
+
+ return 1;
+ }
+
+ bigint_t *quotient = div_res.value.division.quotient;
+ bigint_t *remainder = div_res.value.division.remainder;
+
+ // Print result
+ bigint_printf(
+ "457349545684946456456456567567 / 43569678678678678678678432 (should be 10,496) = %B\
+ \n457349545684946456456456567567 %% 43569678678678678678678432 (should be 42,198,273,535,045,045,047,745,295) = %B\n",
+ quotient, remainder);
+
+ // Destroy big numbers
+ bigint_destroy(x); bigint_destroy(y);
+ bigint_destroy(a); bigint_destroy(b);
+ bigint_destroy(sum); bigint_destroy(diff);
+ bigint_destroy(prod); bigint_destroy(quotient); bigint_destroy(remainder);
+
+ return 0;
+}