Started 'bigint_t' implementation
This commit is contained in:
272
src/bignum.c
Normal file
272
src/bignum.c
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
#define SET_MSG(result, msg) \
|
||||||
|
do { \
|
||||||
|
snprintf((char *)(result).message, RESULT_MSG_SIZE, "%s", (const char *)msg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define COPY_MSG(result, msg) \
|
||||||
|
do { \
|
||||||
|
strncpy((char *)(result).message, (const char *)(msg), RESULT_MSG_SIZE - 1); \
|
||||||
|
(result).message[RESULT_MSG_SIZE - 1] = '\0'; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "bignum.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
// Internal methods
|
||||||
|
static bigint_result_t bigint_trim_zeros(bigint_t *number);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bigint_from_int
|
||||||
|
* @value: an integer value
|
||||||
|
*
|
||||||
|
* Takes an integer and convert it to a big integer
|
||||||
|
*
|
||||||
|
* Returns a big_int_result_t data type containing a new big integer
|
||||||
|
*/
|
||||||
|
bigint_result_t bigint_from_int(long long value) {
|
||||||
|
bigint_result_t result = {0};
|
||||||
|
|
||||||
|
bigint_t *number = malloc(sizeof(bigint_t));
|
||||||
|
if (number == NULL) {
|
||||||
|
result.status = BIGNUM_ERR_ALLOCATE;
|
||||||
|
SET_MSG(result, "Failed to allocate memory for big integer");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector_result_t vec_res = vector_new(4, sizeof(int));
|
||||||
|
if (vec_res.status != VECTOR_OK) {
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_ALLOCATE;
|
||||||
|
COPY_MSG(result, vec_res.message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
number->digits = vec_res.value.vector;
|
||||||
|
number->is_negative = (value < 0);
|
||||||
|
|
||||||
|
if (value < 0) {
|
||||||
|
value = -value;
|
||||||
|
} else if (value == 0) {
|
||||||
|
int zero = 0;
|
||||||
|
vector_result_t push_res = vector_push(number->digits, &zero);
|
||||||
|
if (push_res.status != VECTOR_OK) {
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_INVALID;
|
||||||
|
COPY_MSG(result, vec_res.message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (value > 0) {
|
||||||
|
int digit = value % BIGINT_BASE;
|
||||||
|
vector_result_t push_res = vector_push(number->digits, &digit);
|
||||||
|
if (push_res.status != VECTOR_OK) {
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_INVALID;
|
||||||
|
COPY_MSG(result, vec_res.message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
value /= BIGINT_BASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.status = BIGNUM_OK;
|
||||||
|
SET_MSG(result, "Big integer successfully created");
|
||||||
|
result.value.number = number;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bigint_trim_zeros
|
||||||
|
* @number: a non-null big integer
|
||||||
|
*
|
||||||
|
* Helper function to remove leading zeros
|
||||||
|
*
|
||||||
|
* Returns a bigint_result_t data type
|
||||||
|
*/
|
||||||
|
static bigint_result_t bigint_trim_zeros(bigint_t *number) {
|
||||||
|
bigint_result_t result = {0};
|
||||||
|
|
||||||
|
size_t number_len = vector_size(number->digits);
|
||||||
|
|
||||||
|
while (number_len > 1) {
|
||||||
|
vector_result_t get_res = vector_get(number->digits, number_len - 1);
|
||||||
|
if (get_res.status != VECTOR_OK) {
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_INVALID;
|
||||||
|
COPY_MSG(result, get_res.message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int *last = (int*)get_res.value.element;
|
||||||
|
if (*last != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector_result_t pop_res = vector_pop(number->digits);
|
||||||
|
if (pop_res.status != VECTOR_OK) {
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_INVALID;
|
||||||
|
COPY_MSG(result, get_res.message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
number_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number_len == 1) {
|
||||||
|
vector_result_t get_res = vector_get(number->digits, number_len - 1);
|
||||||
|
if (get_res.status != VECTOR_OK) {
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_INVALID;
|
||||||
|
COPY_MSG(result, get_res.message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int *first = (int*)get_res.value.element;
|
||||||
|
if (*first == 0) {
|
||||||
|
number->is_negative = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.status = BIGNUM_OK;
|
||||||
|
SET_MSG(result, "Big integer successfully trimmed");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bigint_from_string
|
||||||
|
* @string_num: an array of chars representing a number
|
||||||
|
*
|
||||||
|
* Takes a string containing a number and convert it to big integer
|
||||||
|
*
|
||||||
|
* Returns a bigint_result_t data type containing a new big integer
|
||||||
|
*/
|
||||||
|
bigint_result_t bigint_from_string(const char *string_num) {
|
||||||
|
bigint_result_t result = {0};
|
||||||
|
|
||||||
|
if (string_num == NULL || *string_num == 0) {
|
||||||
|
result.status = BIGNUM_ERR_INVALID;
|
||||||
|
SET_MSG(result, "Invalid string");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bigint_t *number = malloc(sizeof(bigint_t));
|
||||||
|
if (number == NULL) {
|
||||||
|
result.status = BIGNUM_ERR_ALLOCATE;
|
||||||
|
SET_MSG(result, "Failed to allocate memory for big integer");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector_result_t vec_res = vector_new(4, sizeof(int));
|
||||||
|
if (vec_res.status != VECTOR_OK) {
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_ALLOCATE;
|
||||||
|
COPY_MSG(result, vec_res.message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
number->digits = vec_res.value.vector;
|
||||||
|
|
||||||
|
number->is_negative = false;
|
||||||
|
if (*string_num == '-') {
|
||||||
|
number->is_negative = true;
|
||||||
|
string_num++;
|
||||||
|
} else if (*string_num == '+') {
|
||||||
|
string_num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the integer is valid or not
|
||||||
|
if (*string_num == '\0') {
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_ALLOCATE;
|
||||||
|
SET_MSG(result, "Invalid integer");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip leading zeros
|
||||||
|
while (*string_num == '0' && *(string_num + 1) != '\0') {
|
||||||
|
string_num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t number_len = strlen(string_num);
|
||||||
|
|
||||||
|
// Process digits from right to left by chunks of the representation base
|
||||||
|
for (int i = number_len; i > 0; i -= BIGINT_BASE_DIGITS) {
|
||||||
|
const int start = (i - BIGINT_BASE_DIGITS > 0) ? i - BIGINT_BASE_DIGITS : 0;
|
||||||
|
const int chunk_len = (i - start);
|
||||||
|
|
||||||
|
int digit = 0;
|
||||||
|
for (int j = 0; j < chunk_len; j++) {
|
||||||
|
digit *= 10 + (string_num[start + j] - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
vector_result_t push_res = vector_push(number->digits, &digit);
|
||||||
|
if (push_res.status != VECTOR_OK) {
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
result.status = BIGNUM_ERR_ALLOCATE;
|
||||||
|
COPY_MSG(result, vec_res.message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bigint_trim_zeros(number);
|
||||||
|
|
||||||
|
result.status = BIGNUM_OK;
|
||||||
|
SET_MSG(result, "Big integer successfully created");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bigint_destroy
|
||||||
|
* @number: a valid big integer
|
||||||
|
*
|
||||||
|
* Deletes the big integer from the memory
|
||||||
|
*
|
||||||
|
* Returns a bigint_result_t data type
|
||||||
|
*/
|
||||||
|
bigint_result_t bigint_destroy(bigint_t *number) {
|
||||||
|
bigint_result_t result = {0};
|
||||||
|
|
||||||
|
if (number == NULL) {
|
||||||
|
result.status = BIGNUM_ERR_INVALID;
|
||||||
|
SET_MSG(result, "Invalid big integer");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector_destroy(number->digits);
|
||||||
|
free(number);
|
||||||
|
|
||||||
|
result.status = BIGNUM_OK;
|
||||||
|
SET_MSG(result, "Big integer successfully deleted");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
49
src/bignum.h
Normal file
49
src/bignum.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#ifndef BIGNUM_H
|
||||||
|
#define BIGNUM_H
|
||||||
|
|
||||||
|
#define RESULT_MSG_SIZE 64
|
||||||
|
|
||||||
|
// Big numbers numerical base (10^9)
|
||||||
|
#define BIGINT_BASE 1000000000
|
||||||
|
// Each digit stores values from 0 to 999,999,999
|
||||||
|
#define BIGINT_BASE_DIGITS 9
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
typedef enum { false = 0x0, true } bool;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BIGNUM_OK = 0x0,
|
||||||
|
BIGNUM_ERR_ALLOCATE,
|
||||||
|
BIGNUM_ERR_DIV_BY_ZERO,
|
||||||
|
BIGNUM_ERR_INVALID
|
||||||
|
} bignum_status_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vector_t *digits;
|
||||||
|
bool is_negative;
|
||||||
|
} bigint_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bignum_status_t status;
|
||||||
|
uint8_t message[RESULT_MSG_SIZE];
|
||||||
|
union {
|
||||||
|
bigint_t *number;
|
||||||
|
char *string_num;
|
||||||
|
} value;
|
||||||
|
} bigint_result_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bigint_result_t bigint_from_int(long long value);
|
||||||
|
bigint_result_t bigint_from_string(const char *string_num);
|
||||||
|
bigint_result_t bigint_destroy(bigint_t *number);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
2
usage.c
2
usage.c
@@ -225,7 +225,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");
|
||||||
|
|||||||
Reference in New Issue
Block a user