Merge pull request #1 from ceticamarco/bignum_experimental

Adding BigInt support
This commit is contained in:
2025-11-18 11:39:18 +01:00
committed by Marco Cetica
19 changed files with 2647 additions and 76 deletions

19
.github/workflows/clang-build.yml vendored Normal file
View File

@@ -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

View File

@@ -1,17 +1,16 @@
name: datum name: gcc-build
on: on: [push,pull_request,workflow_dispatch]
push:
branch: [master]
workflow_dispatch:
jobs: jobs:
build: gcc-build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Build Datum - name: Build Datum
run: | run: |
make clean all make clean all
- name: Run unit tests - name: Run unit tests
run: | run: |
./test_vector && ./test_map ./test_vector && ./test_map && ./test_bigint

View File

@@ -10,13 +10,14 @@ TESTS_SRC = tests
TARGET = usage TARGET = usage
TEST_V_TARGET = test_vector TEST_V_TARGET = test_vector
TEST_M_TARGET = test_map 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 PROG_OBJS = $(OBJ_DIR)/usage.o
.PHONY: all clean .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) $(TARGET): $(PROG_OBJS) $(LIB_OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(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 $(TEST_M_TARGET): $(OBJ_DIR)/test_map.o $(OBJ_DIR)/map.o
$(CC) $(CFLAGS) -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) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<
@@ -40,4 +44,4 @@ $(OBJ_DIR):
mkdir -p $(OBJ_DIR) mkdir -p $(OBJ_DIR)
clean: 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)

View File

@@ -2,7 +2,8 @@
<h1>Datum</h1> <h1>Datum</h1>
<h6><i>Collection of dynamic and generic data structures.</i></h6> <h6><i>Collection of dynamic and generic data structures.</i></h6>
[![](https://github.com/ceticamarco/datum/actions/workflows/datum.yml/badge.svg)](https://github.com/ceticamarco/datum/actions/workflows/datum.yml) [![](https://github.com/ceticamarco/datum/actions/workflows/gcc-build.yml/badge.svg)](https://github.com/ceticamarco/datum/actions/workflows/gcc-build.yml)
[![](https://github.com/ceticamarco/datum/actions/workflows/clang-build.yml/badge.svg)](https://github.com/ceticamarco/datum/actions/workflows/clang-build.yml)
</div> </div>
Datum is a collection of dynamic and generic data structures implemented from scratch in C with no external dependencies beyond 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; - [**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; - [**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 ## Usage
At its simplest, you can use this library as follows: At its simplest, you can use this library as follows:
### `Vector`'s usage ### `Vector` usage
```c ```c
#include <stdio.h> #include <stdio.h>
@@ -51,7 +53,7 @@ int main(void) {
} }
``` ```
### `Map`'s usage ### `Map` usage
```c ```c
#include <stdio.h> #include <stdio.h>
@@ -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 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: 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). management, data ownership, etc.) go to the [docs folder](/docs).
## Unit tests ## 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 ```sh
$ make clean all $ make clean all
$ ./test_vector $ ./test_vector
$ ./test_map $ ./test_map
$ ./test_bigint
``` ```
## License ## License

View File

@@ -7,5 +7,5 @@ At the time being, this documentation includes the following pages:
- [vector.md](vector.md): vector documentation; - [vector.md](vector.md): vector documentation;
- [map.md](map.md): map 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.

92
docs/bigint.md Normal file
View File

@@ -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`.

View File

@@ -71,5 +71,5 @@ typedef struct {
Each method that returns such type indicates whether the operation was successful or not by setting 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 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 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. in the first part of the README.

View File

@@ -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 * Output: Before sorting: -8 20 -10 125 34 9
* After sorting (ascending order): -10 -8 9 20 34 125 * After sorting (ascending order): -10 -8 9 20 34 125
* After sorting (descending order): 125 34 20 9 -8 -10 * After sorting (descending order): 125 34 20 9 -8 -10
@@ -55,9 +55,11 @@ int main(void) {
vector_push(v, &values[idx]); vector_push(v, &values[idx]);
} }
const size_t sz = vector_size(v);
// Print unsorted array // Print unsorted array
printf("Before sorting: "); 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); printf("%d ", *(int*)vector_get(v, idx).value.element);
} }
@@ -66,7 +68,7 @@ int main(void) {
// Print sorted array // Print sorted array
printf("\nAfter sorting (ascending order): "); 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); printf("%d ", *(int*)vector_get(v, idx).value.element);
} }
@@ -75,7 +77,7 @@ int main(void) {
// Print sorted array // Print sorted array
printf("\nAfter sorting (descending order): "); 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); 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: * Output: Sort by age:
* Name: Marco, Age: 25 * Name: Marco, Age: 25
* Name: Alice, Age: 28 * Name: Alice, Age: 28
@@ -149,9 +151,11 @@ int main(void) {
// Sort array by age // Sort array by age
vector_sort(employees, cmp_person_by_age); vector_sort(employees, cmp_person_by_age);
const size_t sz = vector_size(employees);
// Print sorted array // Print sorted array
printf("Sort by age:\n"); 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; Employee *p = (Employee*)vector_get(employees, idx).value.element;
printf("Name: %s, Age: %d\n", p->name, p->age); printf("Name: %s, Age: %d\n", p->name, p->age);
} }
@@ -161,7 +165,7 @@ int main(void) {
// Print sorted array // Print sorted array
printf("\nSort by name:\n"); 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; Employee *p = (Employee*)vector_get(employees, idx).value.element;
printf("Name: %s, Age: %d\n", p->name, p->age); printf("Name: %s, Age: %d\n", p->name, p->age);
} }

View File

@@ -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` 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 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 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 The documentation for the `vector_sort(map, cmp)` method can be found
in [the following document](/docs/sort.md). in [the following document](/docs/sort.md).

1863
src/bigint.c Normal file

File diff suppressed because it is too large Load Diff

64
src/bigint.h Normal file
View File

@@ -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 <stdint.h>
#include <stdbool.h>
#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

View File

@@ -1,5 +1,7 @@
#define SET_MSG(result, msg) \ #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 <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -35,7 +37,7 @@ uint64_t hash_key(const char *key) {
* *
* Returns a map_result_t data type containing a new hash map * 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_result_t result = {0};
map_t *map = malloc(sizeof(map_t)); map_t *map = malloc(sizeof(map_t));

View File

@@ -53,7 +53,7 @@ typedef struct {
extern "C" { extern "C" {
#endif #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_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_get(const map_t *map, const char *key);
map_result_t map_remove(map_t *map, const char *key); map_result_t map_remove(map_t *map, const char *key);

View File

@@ -1,5 +1,7 @@
#define SET_MSG(result, msg) \ #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 <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

381
tests/test_bigint.c Normal file
View File

@@ -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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#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;
}

View File

@@ -15,7 +15,7 @@
#include "../src/map.h" #include "../src/map.h"
// Create a new map // Create a new map
void test_map_new() { void test_map_new(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -27,7 +27,7 @@ void test_map_new() {
} }
// Add elements to map // Add elements to map
void test_map_add() { void test_map_add(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -47,7 +47,7 @@ void test_map_add() {
} }
// Add multiple elements to the map // Add multiple elements to the map
void test_map_add_multiple() { void test_map_add_multiple(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -68,7 +68,7 @@ void test_map_add_multiple() {
} }
// Get map element // Get map element
void test_map_get() { void test_map_get(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -85,7 +85,7 @@ void test_map_get() {
} }
// Get non-existing key from map // Get non-existing key from map
void test_map_get_invalid() { void test_map_get_invalid(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -98,7 +98,7 @@ void test_map_get_invalid() {
} }
// Map with heterogeneous types // Map with heterogeneous types
void test_map_mixed() { void test_map_mixed(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -126,7 +126,7 @@ void test_map_mixed() {
} }
// Update existing map key // Update existing map key
void test_map_update() { void test_map_update(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -149,7 +149,7 @@ void test_map_update() {
} }
// Remove an element from map // Remove an element from map
void test_map_remove() { void test_map_remove(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -177,7 +177,7 @@ void test_map_remove() {
} }
// Remove non-existing key from map // Remove non-existing key from map
void test_map_remove_invalid() { void test_map_remove_invalid(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -190,7 +190,7 @@ void test_map_remove_invalid() {
} }
// Clear the map // Clear the map
void test_map_clear() { void test_map_clear(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -212,7 +212,7 @@ void test_map_clear() {
} }
// Clear empty map // Clear empty map
void test_map_clear_empty() { void test_map_clear_empty(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -226,7 +226,7 @@ void test_map_clear_empty() {
} }
// Multiple operations in sequence (add, update, delete and clear) // Multiple operations in sequence (add, update, delete and clear)
void test_map_sequence() { void test_map_sequence(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -266,7 +266,7 @@ typedef struct {
short age; short age;
} Person; } Person;
void test_map_struct() { void test_map_struct(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);
@@ -298,7 +298,7 @@ void test_map_struct() {
} }
// Test map capacity tracking // Test map capacity tracking
void test_map_cap() { void test_map_cap(void) {
map_result_t res = map_new(); map_result_t res = map_new();
assert(res.status == MAP_OK); assert(res.status == MAP_OK);

Binary file not shown.

View File

@@ -15,7 +15,7 @@
#include "../src/vector.h" #include "../src/vector.h"
// Create a new vector // Create a new vector
void test_vector_new() { void test_vector_new(void) {
vector_result_t res = vector_new(5, sizeof(int)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -27,14 +27,14 @@ void test_vector_new() {
} }
// Create a vector with zero capacity // 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)); vector_result_t res = vector_new(0, sizeof(int));
assert(res.status == VECTOR_ERR_ALLOCATE); assert(res.status == VECTOR_ERR_ALLOCATE);
} }
// Push elements to vector // Push elements to vector
void test_vector_push() { void test_vector_push(void) {
vector_result_t res = vector_new(5, sizeof(int)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -54,7 +54,7 @@ void test_vector_push() {
} }
// Trigger vector reallocation // Trigger vector reallocation
void test_vector_push_realloc() { void test_vector_push_realloc(void) {
vector_result_t res = vector_new(1, sizeof(int)); vector_result_t res = vector_new(1, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -72,7 +72,7 @@ void test_vector_push_realloc() {
} }
// Get vector elements // Get vector elements
void test_vector_get() { void test_vector_get(void) {
vector_result_t res = vector_new(5, sizeof(int)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -89,7 +89,7 @@ void test_vector_get() {
} }
// Test out of bounds // Test out of bounds
void test_vector_get_ofb() { void test_vector_get_ofb(void) {
vector_result_t res = vector_new(5, sizeof(int)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); 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); 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)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -134,7 +134,9 @@ void test_vector_sort_int_asc() {
assert(sort_res.status == VECTOR_OK); assert(sort_res.status == VECTOR_OK);
const int expected[] = { -7, 1, 4, 6, 12, 25, 25, 71 }; 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; int *val = (int*)vector_get(v, idx).value.element;
assert(*val == expected[idx]); assert(*val == expected[idx]);
} }
@@ -142,7 +144,7 @@ void test_vector_sort_int_asc() {
vector_destroy(v); 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)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -157,7 +159,9 @@ void test_vector_sort_int_desc() {
assert(sort_res.status == VECTOR_OK); assert(sort_res.status == VECTOR_OK);
const int expected[] = { 71, 25, 25, 12, 6, 4, 1, -7 }; 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; int *val = (int*)vector_get(v, idx).value.element;
assert(*val == expected[idx]); assert(*val == expected[idx]);
} }
@@ -183,7 +187,7 @@ vector_order_t cmp_string_desc(const void *x, const void *y) {
return VECTOR_ORDER_EQ; return VECTOR_ORDER_EQ;
} }
void test_vector_sort_string() { void test_vector_sort_string(void) {
vector_result_t res = vector_new(5, sizeof(char*)); vector_result_t res = vector_new(5, sizeof(char*));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -198,7 +202,9 @@ void test_vector_sort_string() {
assert(sort_res.status == VECTOR_OK); assert(sort_res.status == VECTOR_OK);
const char *expected[] = { "world!", "system-programming", "hello", "foo", "embedded", "bar"}; 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; const char *val = *(const char**)vector_get(v, idx).value.element;
assert(!strcmp(val, expected[idx])); 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; 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)); vector_result_t res = vector_new(5, sizeof(Person));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -257,7 +263,8 @@ void test_vector_sort_struct_by_age() {
{ .name = "Bob", .age = 45 } { .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; Person *p = (Person*)vector_get(people, idx).value.element;
assert(!strcmp(p->name, expected[idx].name)); assert(!strcmp(p->name, expected[idx].name));
assert(p->age == expected[idx].age); assert(p->age == expected[idx].age);
@@ -266,7 +273,7 @@ void test_vector_sort_struct_by_age() {
vector_destroy(people); 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)); vector_result_t res = vector_new(5, sizeof(Person));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -295,7 +302,8 @@ void test_vector_sort_struct_by_name() {
{ .name = "Sophia", .age = 45 } { .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; Person *p = (Person*)vector_get(people, idx).value.element;
assert(!strcmp(p->name, expected[idx].name)); assert(!strcmp(p->name, expected[idx].name));
assert(p->age == expected[idx].age); assert(p->age == expected[idx].age);
@@ -305,7 +313,7 @@ void test_vector_sort_struct_by_name() {
} }
// Set vector element // Set vector element
void test_vector_set() { void test_vector_set(void) {
vector_result_t res = vector_new(5, sizeof(int)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -324,7 +332,7 @@ void test_vector_set() {
} }
// Set vector element out of bounds // 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)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -340,7 +348,7 @@ void test_vector_set_ofb() {
} }
// Pop element from vector // Pop element from vector
void test_vector_pop() { void test_vector_pop(void) {
vector_result_t res = vector_new(5, sizeof(int)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -361,7 +369,7 @@ void test_vector_pop() {
} }
// Test pop element from empty vector // 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)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -374,7 +382,7 @@ void test_vector_pop_empty() {
} }
// Clear vector // Clear vector
void test_vector_clear() { void test_vector_clear(void) {
vector_result_t res = vector_new(5, sizeof(int)); vector_result_t res = vector_new(5, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -396,7 +404,7 @@ void test_vector_clear() {
} }
// Multiple operations in sequence (push, set, pop and 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)); vector_result_t res = vector_new(2, sizeof(int));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -426,7 +434,7 @@ void test_vector_sequence() {
} }
// Vector with chars // Vector with chars
void test_vector_char() { void test_vector_char(void) {
vector_result_t res = vector_new(5, sizeof(char)); vector_result_t res = vector_new(5, sizeof(char));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);
@@ -449,7 +457,7 @@ typedef struct {
int y; int y;
} Point; } Point;
void test_vector_struct() { void test_vector_struct(void) {
vector_result_t res = vector_new(5, sizeof(Point)); vector_result_t res = vector_new(5, sizeof(Point));
assert(res.status == VECTOR_OK); assert(res.status == VECTOR_OK);

119
usage.c
View File

@@ -20,10 +20,14 @@
#include "src/vector.h" #include "src/vector.h"
#include "src/map.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_asc(const void *x, const void *y);
static vector_order_t cmp_int_desc(const void *x, const void *y);
int main(void) { int main(void) {
int st; int st;
@@ -36,6 +40,11 @@ int main(void) {
st = map_usage(); st = map_usage();
if (st) { return st; } if (st) { return st; }
SEP(50);
st = bigint_usage();
if (st) { return st; }
return 0; return 0;
} }
@@ -53,7 +62,7 @@ vector_order_t cmp_int_desc(const void *x, const void *y) {
return cmp_int_asc(y, x); return cmp_int_asc(y, x);
} }
int vector_usage() { int vector_usage(void) {
// Create a vector of 3 integers // Create a vector of 3 integers
vector_result_t res = vector_new(3, sizeof(int)); vector_result_t res = vector_new(3, sizeof(int));
if (res.status != VECTOR_OK) { if (res.status != VECTOR_OK) {
@@ -79,7 +88,8 @@ int vector_usage() {
printf("Vector capacity (should be > 5): %zu\n\n", vector_capacity(vector)); printf("Vector capacity (should be > 5): %zu\n\n", vector_capacity(vector));
// Print the whole 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); vector_result_t get_res = vector_get(vector, idx);
if (get_res.status != VECTOR_OK) { if (get_res.status != VECTOR_OK) {
printf("Cannot retrieve vec[%zu]: %s\n", idx, get_res.message); printf("Cannot retrieve vec[%zu]: %s\n", idx, get_res.message);
@@ -127,7 +137,9 @@ int vector_usage() {
} }
printf("Added new elements. Before sort: "); 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); vector_result_t sort_get_res = vector_get(vector, idx);
if (sort_get_res.status != VECTOR_OK) { if (sort_get_res.status != VECTOR_OK) {
printf("Cannot retrieve vec[%zu]: %s\n", idx, sort_get_res.message); 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: "); 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); vector_result_t sort_get_res = vector_get(vector, idx);
if (sort_get_res.status != VECTOR_OK) { if (sort_get_res.status != VECTOR_OK) {
printf("Cannot retrieve vec[%zu]: %s\n", idx, sort_get_res.message); 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: "); 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); vector_result_t sort_get_res = vector_get(vector, idx);
if (sort_get_res.status != VECTOR_OK) { if (sort_get_res.status != VECTOR_OK) {
printf("Cannot retrieve vec[%zu]: %s\n", idx, sort_get_res.message); printf("Cannot retrieve vec[%zu]: %s\n", idx, sort_get_res.message);
@@ -194,7 +206,7 @@ int vector_usage() {
return 0; return 0;
} }
int map_usage() { int map_usage(void) {
// Create a new map // Create a new map
map_result_t res = map_new(); map_result_t res = map_new();
if (res.status != MAP_OK) { if (res.status != MAP_OK) {
@@ -225,7 +237,7 @@ int map_usage() {
// Print size and capacity // Print size and capacity
printf("Map size (should be 2): %zu\n", map_size(map)); 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 // Retrieve keys
map_result_t get_res = map_get(map, "x"); 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("Map cleared (size should be 0): %zu\n", map_size(map));
} }
printf("\n");
// Delete the map // Delete the map
map_result_t del_res = map_destroy(map); map_result_t del_res = map_destroy(map);
if (del_res.status != MAP_OK) { if (del_res.status != MAP_OK) {
@@ -292,3 +306,90 @@ int map_usage() {
return 0; 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;
}