diff --git a/demos/big_number.c b/demos/big_number.c new file mode 100644 index 0000000000000000000000000000000000000000..909f62650311e29eb4063929b050ecc29bebb56a --- /dev/null +++ b/demos/big_number.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "common_errno.h" +#include "common_interface.h" + +int main() { + char result[1024] = { 0 }; + int olen = 0; + + char left[] = "123"; + char right[] = "222"; + + int ret = 0; + + ret = common_big_number_plus(result, &olen, sizeof(result), left, right); + result[olen] = '\0'; + printf("ret is %d\n", ret); + printf("%s\n", result); + memset(result, 0, sizeof(result)); + + ret = common_big_number_subtraction(result, &olen, sizeof(result), left, right); + result[olen] = '\0'; + printf("ret is %d\n", ret); + printf("%s\n", result); + memset(result, 0, sizeof(result)); + + ret = common_big_number_subtraction(result, &olen, sizeof(result), right, left); + result[olen] = '\0'; + printf("ret is %d\n", ret); + printf("%s\n", result); + memset(result, 0, sizeof(result)); + + ret = common_big_number_multiplication(result, &olen, sizeof(result), left, right); + result[olen] = '\0'; + printf("ret is %d\n", ret); + printf("%s\n", result); + memset(result, 0, sizeof(result)); + + return 0; +} \ No newline at end of file diff --git a/demos/list.c b/demos/list.c index 4b46111c959dfac09574aa73f4774bfcb3765c86..115ff148436aa031fad13ae3080870a935bc956a 100644 --- a/demos/list.c +++ b/demos/list.c @@ -11,7 +11,6 @@ int main() { int i = 0; int *temp = NULL; int8_t size = 0; - int get = 0; ret = list_init(&handler); if(ret != LIST_OK) { @@ -31,7 +30,7 @@ int main() { temp = NULL; - ret = list_size(handler, &size); + ret = list_size(handler, (int64_t *)&size); if(ret != LIST_OK) { printf("list get isze error, code: 0x%04x\n", ret); goto exit; @@ -39,7 +38,7 @@ int main() { printf("list size is %d\n", size); for(i = 0; i < 10; i++) { - ret = list_get_at(handler, i + 1, &temp); + ret = list_get_at(handler, i + 1, (void **)&temp); if(ret != LIST_OK) { printf("list get error, code: 0x%04x\n", ret); goto exit; @@ -55,7 +54,7 @@ int main() { goto exit; } for(i = 0; i < 9; i++) { - ret = list_get_at(handler, i + 1, &temp); + ret = list_get_at(handler, i + 1, (void **)&temp); if(ret != LIST_OK) { printf("list get error, code: 0x%04x\n", ret); goto exit; @@ -73,7 +72,7 @@ int main() { goto exit; } for(i = 0; i < 10; i++) { - ret = list_get_at(handler, i + 1, &temp); + ret = list_get_at(handler, i + 1, (void **)&temp); if(ret != LIST_OK) { printf("list get error, code: 0x%04x\n", ret); goto exit; diff --git a/include/common_errno.h b/include/common_errno.h index edb8c77197b982308bbfc4b47c0f3cd12554e42f..c7efcff3e482eb663c19db0bee1399a0627bd036 100644 --- a/include/common_errno.h +++ b/include/common_errno.h @@ -9,4 +9,9 @@ #define COM_MEM_LESS 0x0002 /* < 内存资源紧张,无法申请内存 */ #define COM_BUF_SMALL 0x0003 /* < buffer太小,请更换大的buffer */ #define COM_ERR_LENGTH 0x0004 /* < 文件长度过长,应当小于256个字符 */ -#define COM_ERR_FILE_NOT_EXISTS 0x0005 /* < 文件不存在 */ \ No newline at end of file +#define COM_ERR_FILE_NOT_EXISTS 0x0005 /* < 文件不存在 */ + +#define COM_BIG_NUMBER_OUT_BUF_SMALL 0x0100 /* < 存放结果的buff太小,无法装下整个运算结果 */ +#define COM_BIG_NUMBER_NOT_NUMBER 0x0101 /* < 输入的数字字符串非法 */ + +#define COM_ERR_UNKNOWN 0xffff /* < 不应该发生的错误,未知错误 */ \ No newline at end of file diff --git a/include/common_interface.h b/include/common_interface.h index 4f8bfccab2c16b0a758162747cfbc24c68a6e1fe..7c8d3064abbf2d4f1f78c74819122e8f5ce52e2f 100644 --- a/include/common_interface.h +++ b/include/common_interface.h @@ -181,4 +181,40 @@ int common_byte_8_set(uint64_t *in, common_byte_type byte_type, int position); */ int common_byte_8_get(uint64_t *in, common_byte_type *byte_type, int position); +/** + * @brief 大数加法 + * + * @param out[out] 运算结果 + * @param olen[out] 结果长度 + * @param out_size[in] buffer大小 + * @param left[in] 左操作数 + * @param right[in] 右操作数 + * @return #COM_OK 操作成功 + */ +int common_big_number_plus(char *out, int *olen, int out_size, const char left[], const char right[]); + +/** + * @brief 大数减法 + * + * @param out[out] 运算结果 + * @param olen[out] 结果长度 + * @param out_size[in] buffer大小 + * @param left[in] 左操作数 + * @param right[in] 右操作数 + * @return #COM_OK 操作成功 + */ +int common_big_number_subtraction(char *out, int *olen, int out_size, const char left[], const char right[]); + +/** + * @brief 大数乘法 + * + * @param out[out] 运算结果 + * @param olen[out] 结果长度 + * @param out_size[in] buffer大小 + * @param left[in] 左操作数 + * @param right[in] 右操作数 + * @return #COM_OK 操作成功 + */ +int common_big_number_multiplication(char *out, int *olen, int out_size, const char left[], const char right[]); + #endif \ No newline at end of file diff --git a/src/common_interface.c b/src/common_interface.c index 0c67f06a1195ea43f30cb09b661adbc8e45e71af..f71a704ff750e3d40f5cc33858c79456d63a3b33 100644 --- a/src/common_interface.c +++ b/src/common_interface.c @@ -7,10 +7,33 @@ #include #include #include +#include #define COMMON_SIZE_UINT32_T 4 //范围 #define COMMON_PATH_MAX 256 //路径最大长度 +// 内部布尔类型 +typedef enum { + COMMON_BOOL_FALSE, + COMMON_BOOL_TRUE, + COMMON_BOOL_MAX, +}common_bool; + +// 数字正负性 +typedef enum { + COMMON_OPERATE_NEGATIVE, + COMMON_OPERATE_POSITIVE, + COMMON_OPERATE_MAX, +}common_operate; + +// 数字大小比较 +typedef enum { + COMMON_COMPARE_BIGGER, + COMMON_COMPARE_SMALLER, + COMMON_COMPARE_EQUAL, + COMMON_COMPARE_MAX, +}common_compare; + /** * 判断大小端 */ @@ -201,3 +224,529 @@ int common_byte_8_get(uint64_t *in, common_byte_type *byte_type, int position) { return COM_OK; } + +// 检查一个输入大数是否为合法数字 +static int internal_check_str_is_number(const char number[]) { + int length = strlen(number); + int i = 0; + for(i = 0; i < length; i++) { + if(!((number[i] >= '0' && number[i] <= '9') || (number[i] == '-' || number[i] == '+'))) { + return 0; + } + } + return 1; +} + +// 内部加法算法,左加右,不考虑符号 +static int internal_plus(char *out, int *olen, int osize, const char left[], int length_left, const char right[], int length_right) { + int *result = NULL; + int result_size = length_left > length_right ? length_left + 1 : length_right + 1; + int result_count = 0; + int ret = COM_OK; + + int left_number = 0; + int right_number = 0; + int l = 0, r = 0; + + int i; + + int temp = 0; + + result = (int *)malloc(sizeof(int) * result_size); + if(result == NULL) { + ret = COM_MEM_LESS; + goto exit; + } + memset(result, 0, sizeof(int) * result_size); + + l = length_left - 1; + r = length_right - 1; + result_count = 0; + + // 赋值给int数组 + while(result_count < result_size && (l >= 0 || r >= 0)) { + left_number = 0; + right_number = 0; + // 拿到数字 + if(l >= 0) { + left_number = left[l] - '0'; + l--; + } + if(r >= 0) { + right_number = right[r] - '0'; + r--; + } + result[result_count] = left_number + right_number; + result_count++; + } + + // 从前向后进行进位操作 + for(i = 0; i < result_count && i < result_size; i++) { + if(result[i] >= 10) { + result[i + 1] += result[i] / 10; + result[i] %= 10; + if(i == result_count - 1) { + result_count++; + } + } + } + + // 从后向前赋值给out数组 + temp = 0; + for(i = result_count - 1; i >= 0 && temp < result_size; i--) { + out[temp] = result[i] + '0'; + temp++; + } + *olen = temp; + +exit: + if(result != NULL) { + free(result); + } + return ret; + +} + +// 内部减法算法,左减右,不考虑符号,左操作数一定是大于右操作数 +static int internal_subtraction(char *out, int *olen, int osize, const char left[], int left_size, const char right[], int right_size) { + int ret = COM_OK; + int *result = NULL; + int result_count = 0; + int result_size = left_size > right_size ? left_size : right_size; + + int i = 0; + int temp = 0; + + int l = 0, r = 0; + int number_left = 0, number_right = 0; + + result = (int *)malloc(sizeof(int) * result_size); + if(result == NULL) { + ret = COM_MEM_LESS; + goto exit; + } + memset(result, 0, sizeof(int) * result_size); + internal_debug("result init ok\n"); + + // 将两个操作数,直接left - right存放到result中,尽管会有负数,但是后面能够统一处理 + result_count = 0; + l = left_size - 1; + r = right_size - 1; + while(result_count < result_size && (l >= 0 || r >= 0)) { + number_left = 0; + number_right = 0; + if(l >= 0) { + number_left = left[l] - '0'; + l--; + } + if(r >= 0) { + number_right = right[r] - '0'; + r--; + } + result[result_count] = number_left - number_right; + result_count++; + } + + // 一次遍历,消除掉所有的借位情况 + for(i = 0; i < result_count; i++) { + if(result[i] < 0) { + result[i] += 10; + result[i + 1] --; + if(i == result_count - 1 && result[i + 1] == 0) { + result_count--; + } + } + internal_debug("%d\n", result[i]); + } + + // 一次遍历,复制到out中 + temp = 0; + for(i = result_count - 1; i >= 0 && temp < osize; i--) { + out[temp] = result[i] + '0'; + temp++; + } + *olen = temp; + internal_debug("%d\n", temp); + ret = COM_OK; + +exit: + if(result != NULL) { + free(result); + } + return ret; +} + +// 比较两个大数的大小,bigger代表number1大,smaller代表number2大,equal代表两者相等 +static common_compare internal_compare(const char number1[], const char number2[]) { + const char *head_number1 = NULL; + const char *head_number2 = NULL; + + int length_number1 = 0; + int length_number2 = 0; + + int i = 0; + + int temp = 0; + while(!(number1[temp] >= '0' && number1[temp] <= '9')) { + temp++; + } + head_number1 = number1 + temp; + + temp = 0; + while(!(number2[temp] >= '0' && number2[temp] <= '9')) { + temp++; + } + head_number2 = number2 + temp; + + length_number1 = strlen(head_number1); + length_number2 = strlen(head_number2); + + if(length_number1 > length_number2) { + return COMMON_COMPARE_BIGGER; + } + if(length_number1 < length_number2) { + return COMMON_COMPARE_SMALLER; + } + + for(i = 0; i < length_number1; i++) { + if(head_number1[i] > head_number2[i]) { + return COMMON_COMPARE_BIGGER; + } + else if(head_number1[i] < head_number2[i]) { + return COMMON_COMPARE_SMALLER; + } + } + + return COMMON_COMPARE_EQUAL; +} + +// 去除前导零 +static void internal_clear_front_zero(char input[], int *olen) { + int length = *olen; + int counter = 0; + int i = 0; + while(input[i] == '0') { + i++; + } + for(; i < length; i++) { + input[counter] = input[i]; + counter++; + } + *olen = counter; +} + +// 获得符号 +common_operate internal_get_operate(const char number[]) { + if(number[0] == '-') { + return COMMON_OPERATE_NEGATIVE; + } + return COMMON_OPERATE_POSITIVE; +} + +/** + * 大数加法算法(带符号数字): +1. 输入判断 +2. 判断输入符号是否同号,同号视为相加,异号视为相减,使用common_bool is_same,true为同号,false为异号 + 2.1. 同号状态下,直接使用int走一遍即可,从后向前 + 2.1.1. 如果都是负号,则输出结果头带上负号 + 2.1.2. 修正完符号后进行加法计算 + 2.2. 异号状态下,视为减法运算 + 2.2.1. 如果左操作数为负号 + 2.2.1.1. 如果左操作数比右操作数大,调用公共减接口,结束后将结果赋值-号,结果为负数 + 2.2.1.2. 如果右操作数比左操作数大,调用公共减接口时需要调换顺序,结束后无需赋值符号,结果为正数 + 2.2.2. 如果右操作数为负号 + 2.2.2.1. 如果左操作数比右操作数大,调用公共减接口,结束后无需赋值符号,结果为正数 + 2.2.2.2. 如果右操作数比左操作数大,调用公共减接口时需要调换顺序,结束后赋值-号,结果为负数 + +*/ +int common_big_number_plus(char *out, int *olen, int out_size, const char left[], const char right[]) { + int length_left = 0, length_right = 0; // 左右运算数长度 + int ret = COM_BAD_INPUT; + + const char *head_left = NULL; + const char *head_right = NULL; + int temp = 0; + + // 运算符 + common_operate operate_left = COMMON_OPERATE_MAX, operate_right = COMMON_OPERATE_MAX; + // 是否为同号 + common_bool is_same_operate = COMMON_BOOL_FALSE; + // 谁大谁小 + common_compare compare = COMMON_COMPARE_MAX; + + // step 1 输入判断 + if(out == NULL || olen == NULL || left == NULL || right == NULL) { // 输入检测 + return COM_BAD_INPUT; + } + + if((!internal_check_str_is_number(left)) || (!internal_check_str_is_number(right))) { // 数字是否合法检测 + return COM_BIG_NUMBER_NOT_NUMBER; + } + + length_left = strlen(left); + length_right = strlen(right); + + if(out_size < length_left || out_size < length_right) { // buffer太小,无法装下运算结果 + return COM_BIG_NUMBER_OUT_BUF_SMALL; + } + + // step 2 判断符号是否相同 + // 拿到符号 + operate_left = internal_get_operate(left); + operate_right = internal_get_operate(right); + + // 判断符号是否相同 + if(operate_left == operate_right) { + is_same_operate = COMMON_BOOL_TRUE; + } + else { + is_same_operate = COMMON_BOOL_FALSE; + } + + // step 2.1 同号视为相加 + if(is_same_operate == COMMON_BOOL_TRUE) { + if(operate_left == COMMON_OPERATE_NEGATIVE) { + internal_debug("operate is negative\n"); + ret = internal_plus(out + 1, olen, out_size - 1, left + 1, length_left - 1, right + 1, length_right - 1); + out[0] = '-'; + *olen = (*olen) + 1; + } + else { + internal_debug("operate is positive\n"); + ret = internal_plus(out, olen, out_size, left, length_left, right, length_right); + } + goto exit; + } + // step 2.2 不同符号 + else { + internal_debug("start to compare\n"); + // 比较大小 + compare = internal_compare(left, right); + internal_debug("compare is %d\n", compare); + if(compare == COMMON_COMPARE_EQUAL) { + internal_debug("equal\n"); + out[0] = '0'; + *olen = 1; + ret = COM_OK; + goto exit; + } + internal_debug("compare ok\n"); + + // 过滤掉符号的影响 + temp = 0; + while(!(left[temp] >= '0' && left[temp] <= '9')) { + temp++; + } + head_left = left + temp; + length_left -= temp; + internal_debug("temp = %d\n", temp); + + temp = 0; + while(!(right[temp] >= '0' && right[temp] <= '9')) { + temp++; + } + head_right = right + temp; + length_right -= temp; + internal_debug("temp = %d\n", temp); + + + // step 2.2.1 左操作数为负数 + if(operate_left == COMMON_OPERATE_NEGATIVE) { + // step 2.2.1.1 左操作数比右操作数大 + if(compare == COMMON_COMPARE_BIGGER) { + internal_debug("step 2.2.1.1\n"); + out[0] = '-'; + ret = internal_subtraction(out + 1, olen, out_size - 1, head_left, length_left, head_right, length_right); + *olen = (*olen) + 1; + goto exit; + } + // step 2.2.1.2 右操作数比左操作数大 + else { + internal_debug("step 2.2.1.2\n"); + ret = internal_subtraction(out, olen, out_size, head_right, length_right, head_left, length_left); + goto exit; + } + } + // step 2.2.2 右操作数为负数 + else if(operate_right == COMMON_OPERATE_NEGATIVE) { + // step 2.2.2.1 左操作数比右操作数大 + if(compare == COMMON_COMPARE_BIGGER) { + internal_debug("step 2.2.2.1\n"); + ret = internal_subtraction(out, olen, out_size, head_left, length_left, head_right, length_right); + goto exit; + } + // step 2.2.2.2 右操作数比左操作数大 + else { + internal_debug("step 2.2.2.2\n"); + out[0] = '-'; + ret = internal_subtraction(out + 1, olen, out_size - 1, head_right, length_right, head_left, length_left); + *olen = (*olen) + 1; + goto exit; + } + } + } + +exit: + internal_clear_front_zero(out, olen); + return ret; + +} + +/** + * 大数减法算法思想: + * 1. 左操作数取反,调用大数加法即可 +*/ +int common_big_number_subtraction(char *out, int *olen, int out_size, const char left[], const char right[]) { + int length = 0; + int i = 0; + int ret = 0; + + if(right == NULL) { + return COM_BAD_INPUT; + } + + length = strlen(right); + + if(length <= 0) { + return COM_BAD_INPUT; + } + + char *temp = (char *)malloc(sizeof(char) * (length + 5)); + + memset(temp, 0, length + 5); + + if(right[0] == '-') { + for(i = 1; i < length; i++) { + temp[i - 1] = right[i]; + } + } + else { + temp[0] = '-'; + for(i = 0; i < length; i++) { + temp[i + 1] = right[i]; + } + } + + ret = common_big_number_plus(out, olen, out_size, left, temp); + + free(temp); + return ret; +} + +/** + * 大数乘法算法思想: + * 1. out_size >= (strlen(left) > strlen(right) ? strlen(left) : strlen(right)) * 2 ? 进行下一步 : return COM_BIG_NUMBER_OUT_BUF_SMALL + * 2. 判断结果的正负性 + * 3. 开始按位进行乘法运算,要记住偏移位数,直接存放到out中 + * 4. 将数字转换成字符串 + * 5. 处理前导零 + * 6. 赋值olen + */ +int common_big_number_multiplication(char *out, int *olen, int out_size, const char left[], const char right[]) { + int length_left = 0, length_right = 0; + int i = 0, j = 0; + // 正负性,0是负数,1是正数 + common_operate is_positive = COMMON_OPERATE_MAX; + // 输出数组base + int out_base = 0; + // 中间结果 + int64_t *temp = NULL; + int ret = COM_BAD_INPUT; + + // 过滤掉符号位的指针 + const char *head_left = NULL, *head_right = NULL; + + if(out == NULL || olen == NULL || left == NULL || right == NULL) { // 输入检测 + return COM_BAD_INPUT; + } + + if(!internal_check_str_is_number(left) || !internal_check_str_is_number(right)) { // 数字是否合法检测 + return COM_BIG_NUMBER_NOT_NUMBER; + } + + length_left = strlen(left); + length_right = strlen(right); + + // step1: 判断buffer + if(out_size < length_left * 2 || out_size < length_right * 2) { // buffer太小 + return COM_BIG_NUMBER_OUT_BUF_SMALL; + } + + // step2: 判断正负性 + if((left[0] != '-' && right[0] != '-') || (left[0] == '-' && left[0] == '-')) { + is_positive = COMMON_OPERATE_POSITIVE; + } + else { + is_positive = COMMON_OPERATE_NEGATIVE; + } + + // 过滤掉符号 + i = 0; + while(left[i] < '0' || left[i] > '9') { + i++; + } + head_left = left + i; + length_left -= i; + + i = 0; + while(right[i] < '0' || right[i] > '9') { + i++; + } + head_right = right + i; + length_right -= i; + + // 申请内存 + temp = (int64_t *)malloc(sizeof(int64_t) * out_size); + if(temp == NULL) { + ret = COM_MEM_LESS; + goto exit; + } + memset(temp, 0, sizeof(int64_t) * out_size); + // 赋值base + out_base = 0; + + // step3: 按位进行乘法运算 + for(i = length_left - 1; i >= 0; i--) { + for(j = length_right - 1; j >= 0; j--) { + temp[out_base + length_right - 1 - j] += (head_left[i] - '0') * (head_right[j] - '0'); + } + out_base++; + } + out_base += length_right - 1; + + // step4: 处理数字进位 + for(i = 0; i < out_base; i++) { + if(temp[i] >= 10) { + temp[i + 1] += temp[i] / 10; + temp[i] = temp[i] % 10; + if(i == out_base - 1) { + out_base++; + } + } + } + + // step5: 复制到结果中 + i = 0; + if(is_positive == COMMON_OPERATE_NEGATIVE) { + out[0] = '-'; + i = 1; + } + + for(j = 0; j < out_base; j++) { + internal_debug("%d\n", temp[j]); + } + + for(j = 0; j < out_base; j++) { + out[i] = temp[out_base - 1 - j] + '0'; + i++; + } + + *olen = i; + + ret = COM_OK; + +exit: + free(temp); + + return ret; +} \ No newline at end of file diff --git a/src/list.c b/src/list.c index 518e8d62a6de332151b514bed39c781b132e01da..8c1446f18abfe7b595f5cb395a740a14372f17b3 100644 --- a/src/list.c +++ b/src/list.c @@ -255,7 +255,6 @@ int list_free_all(list **handler) { while(head != NULL) { if(head->data != NULL) { - int *t = head->data; free(head->data); } temp = head; diff --git a/test/check_interface.c b/test/check_interface.c index c4aa5305d027bd17877edcd8de7e16f544d68e1c..dfa8d036569680a3ab96071254051859f3902fc0 100644 --- a/test/check_interface.c +++ b/test/check_interface.c @@ -4,7 +4,7 @@ int main() { SRunner *sr; - int number_failed = 0; + // int number_failed = 0; sr = srunner_create(check_base64()); srunner_add_suite(sr, check_byte()); @@ -13,7 +13,7 @@ int main() srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all (sr, CK_VERBOSE); - number_failed = srunner_ntests_failed(sr); + // number_failed = srunner_ntests_failed(sr); srunner_free(sr); return 0;