所谓大数,就是超过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;
}
在求商的运算中,如果商的值太大,就会出现运算时间很长的情况。