C语言实现大数计算
所谓大数,就是超过longlong表示的位数。
#include<stdio.h> #include<stdlib.h> #include<string.h> #define BASE (10) #define MAX(x, y) ((x) > (y) ? (x) : (y)) typedef struct bignumber_s { char sign; int len; char data[]; }bignumber_s; bignumber_s *calc_add(bignumber_s *a, bignumber_s *b); bignumber_s *calc_sub(bignumber_s *a, bignumber_s *b); bignumber_s *make_bignumber_temp(int len, int sign) { bignumber_s *temp = malloc(sizeof(bignumber_s) + len); if (NULL == temp) { perror("Malloc"); exit(-1); } temp->sign = sign; temp->len = len; memset(temp->data, 0, len); return temp; } const char *strip_str(const char *str) { int i = 0; int len = strlen(str); for (; i < len - 1 && str[i] == '0'; i++) { ; } return str+i; } void fill_data_fromstr(bignumber_s *n, const char *str) { int i = 0; int len = n->len; for (; i < len; i++) { int d = str[len - 1 - i] -'0'; if (d >= 0 && d <= 9) { n->data[i] = d; } else { fprintf(stderr, "Invalid Number:%s\n", str); exit(-1); } } } bignumber_s *make_bignumber_fromstr(const char *str) { int sign = 0; if (str[0] == '-') { sign = 1; str++; } const char *striped_str = strip_str(str); int len = strlen(striped_str); bignumber_s *temp = make_bignumber_temp(len, sign); fill_data_fromstr(temp, striped_str); return temp; } void print_bignumber(bignumber_s *b) { int len = b->len; char *str = malloc(len+1); int i = 0; for(; i < len; i++) { str[i] = b->data[len-i-1] + '0'; } str[len] = '\0'; fprintf(stdout, "%s%s\n", b->sign == 1 ? "-":"", strip_str(str)); free(str); } void usage(const char *s) { fprintf(stderr, "Usage:%s number +-x/ number2.\n", s); exit(-1); } void add_impl(bignumber_s *a, bignumber_s *b, bignumber_s *r) { int i = 0; char carry = 0; int len = r->len; for(; i < len; i++) { if (i < a->len) { carry += a->data[i]; } if (i < b->len) { carry += b->data[i]; } r->data[i] = carry % BASE; carry /= BASE; } } bignumber_s *calc_add(bignumber_s *a, bignumber_s *b) { if (a->sign == b->sign) { int len = MAX(a->len, b->len) + 1; bignumber_s *result = make_bignumber_temp(len, a->sign); add_impl(a, b, result); return result; } else if (a->sign == 0 && b->sign == 1) { b->sign = 0; return calc_sub(a, b); } else if (a->sign == 1 && b->sign == 0) { a->sign = 0; return calc_sub(b, a); } } void sub_impl(bignumber_s *a, bignumber_s *b, bignumber_s *r) { int i = 0; int borrow = 0; int len = r->len; int temp = 0; for (i = 0; i < len; i++) { temp = a->data[i] + BASE - borrow - ((i < b->len) ? b->data[i]:0); r->data[i] = temp % BASE; borrow = temp/BASE ? 0 : 1; } } int valid_len(bignumber_s *a) { int len = a->len; int i = len - 1; for (i = len - 1; i >= 0; i--) { if(a->data[i] == 0) { len--; } else { break; } } return len; } int cmp(bignumber_s *a, bignumber_s *b) { if (a->sign == 0 && b->sign == 1) { return 1; } if (a->sign == 1 && b->sign == 0) { return -1; } int sign = a->sign; int alen = valid_len(a); int blen = valid_len(b); if (alen > blen) { return (sign == 1 ? -1 : 1); } else if (alen < blen) { return (sign == 1 ? 1 : -1); } else { int i = 0; int len = alen; for (i = len - 1; i >= 0; i--) { if (a->data[i] > b->data[i]) { return (sign == 1? -1:1); } else if (a->data[i] < b->data[i]) { return (sign == 1 ? 1 : -1); } } return 0; } } bignumber_s *calc_sub(bignumber_s *a, bignumber_s *b) { if (a->sign == 0 && b->sign == 0) { if (cmp(a, b) >= 0) { int len = a->len; bignumber_s *result= make_bignumber_temp(len, 0); sub_impl(a, b, result); return result; } else { int len = b->len; bignumber_s *result = make_bignumber_temp(len, 1); sub_impl(b, a, result); return result; } } else if (a->sign == 1 && b->sign == 1) { b->sign = 0; a->sign = 0; return calc_sub(b, a); } else if (a->sign == 0 && b->sign == 1) { b->sign = 0; bignumber_s *result = calc_add(a, b); return result; } else if (a->sign == 1 && b->sign == 0) { a->sign = 0; bignumber_s *result = calc_add(a, b); result->sign = 1; return result; } } void mul_impl(bignumber_s *x, bignumber_s *y, bignumber_s *z) { int n = x->len; int m = y->len; int i = 0; int j = 0; int carry = 0; for (; i < m; i++) { for (j = 0; j < n; j++) { carry += y->data[i] * x->data[j] + z->data[i+j]; z->data[i+j] = carry % BASE; carry /= BASE; } for (; j + i < m + n; j++) { carry += z->data[i+j]; z->data[i+j] = carry % BASE; carry /= BASE; } } } bignumber_s *calc_mul(bignumber_s *a, bignumber_s *b) { bignumber_s *zero = make_bignumber_temp(1,0); if (cmp(a, zero) == 0 || cmp(b, zero) == 0) { return zero; } int len = a->len + b->len; bignumber_s *result = make_bignumber_temp(len, a->sign == b->sign ? 0 : 1); mul_impl(a, b, result); return result; } void plusone(bignumber_s *a) { int len = a->len; int i; int carry = 1; for (i = 0; i < len; i++) { carry += a->data[i]; a->data[i] = carry % BASE; carry /= BASE; } } bignumber_s *calc_div(bignumber_s *a, bignumber_s *b) { bignumber_s *zero = make_bignumber_temp(1, 0); if (cmp(b, zero) == 0) { fprintf(stderr, "Interfer division by zero\n"); exit(-1); } else if (cmp(a, zero) == 0) { return zero; } int len = a->len; bignumber_s *result = make_bignumber_temp(len, a->sign == b->sign ? 0 : 1); a->sign = 0; b->sign = 0; bignumber_s *temp = make_bignumber_temp(len, 0); bignumber_s *aa = a; while (1) { if (cmp(aa, b) >= 0) { sub_impl(aa, b, temp); plusone(result); aa = temp; } else { free(temp); return result; } } } int main(int argc, char *argv[]) { char str1[1024] = {0}; char operator[3] = {0}; char str2[1024] = {0}; //scanf("%s %s %s", str1, operator, str2); scanf("%s", str1); scanf("%s", operator); scanf("%s", str2); bignumber_s *a = make_bignumber_fromstr(str1); bignumber_s *b = make_bignumber_fromstr(str2); if (0 == strcmp(operator, "+")) { print_bignumber(calc_add(a, b)); } else if (0 == strcmp(operator, "-")) { print_bignumber(calc_sub(a, b)); } else if (0 == strcmp(operator, "x")) { print_bignumber(calc_mul(a, b)); } else if (0 == strcmp(operator, "/")) { print_bignumber(calc_div(a, b)); } else { usage(argv[0]); } return 0; }
在求商的运算中,如果商的值太大,就会出现运算时间很长的情况。