/*
* file name : calculatorv4.c
* desp : calculator version 4
*/
#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; // 代表大数的符号,1为负数,0为正数
int len; // 代表大数的位数
char data[]; // 大数的数据内容,data[0]代表个位,data[1]代表十位,data[2]代表百位....
} bignumber_s;
bignumber_s* calc_add (bignumber_s* a, bignumber_s* b);
bignumber_s* calc_sub (bignumber_s* a, bignumber_s* b);
// 构造大数模板,len指向大数的数据位数,sign表示该大数的符号
bignumber_s* make_bignumber_temp (int len, int sign) {
// 分配bignumber_s及其所代表数据 所需的内存
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;
}
// 处理数字字符串冗余的0,即"00123" -> "123"
const char* strip_str (const char* str) {
int i = 0;
int len = strlen (str);
for (i = 0; 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 = 0; 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) {
// 处理负数字符串,即"-123"
int sign = 0;
if (str[0] == '-') {
sign = 1;
str++;
}
// 处理数字字符串冗余的0,即"00123" -> "123"
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 = 0; 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 number1 +-x/ number2.\n", s);
exit (-1);
}
// 实现无符号加法,a和b为加数,r为和
void add_impl (bignumber_s* a, bignumber_s* b, bignumber_s* r) {
int i = 0;
char carry = 0;
int len = r->len;
for (i = 0; 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) {
// n位数+m位数,其和最大为max(n,m)+1位数
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; //b数去绝对值
return calc_sub (a, b);
} else if (a->sign == 1 && b->sign == 0) {//情况三
a->sign = 0; //a数去绝对值
return calc_sub (b, a);
}
}
// 实现无符号减法,a-b , r为差
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;
}
// 判断两个大数的大小
// a > b 返回1 ,a<b 返回 -1 , a==b 返回0
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) { // 被减数大于等于减数,即差大于等于0时
int len = a->len;
bignumber_s* result = make_bignumber_temp (len, 0);
sub_impl (a, b, result);
return result;
} else { // 被减数小于减数,即差小于0时
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);
result->sign = 0;
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;
}
}
// 实现无符号乘法,x * y , z为积
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 = 0; i < m; i++) {
// y的每一位乘以x,即计算y[i] * x[0...n] 并累加到z[i...i+n]中
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;
}
// 将剩余的进位,继续在z[i+n...n+m]中累加,从而完成y[i]乘以x[0...n]其积累加到z[i...m+n]中
for (; j + i < n + m; 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);
//乘数当中有0,直接返回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); //a->sign==b->sign为情况一,否则为情况二。
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) {// 除数为0 报错
fprintf (stderr, "Integer division by zero\n");
exit (-1);
} else if (cmp (a, zero) == 0) { // 被除数为0 ,结果为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[]) {
bignumber_s* a = make_bignumber_fromstr (argv[1]);
bignumber_s* b = make_bignumber_fromstr (argv[3]);
if (argc != 4) usage (argv[0]);
if (0 == strcmp (argv[2], "+"))
print_bignumber (calc_add (a, b));
else if (0 == strcmp (argv[2], "-"))
print_bignumber (calc_sub (a, b));
else if (0 == strcmp (argv[2], "x"))
print_bignumber (calc_mul (a, b));
else if (0 == strcmp (argv[2], "/"))
print_bignumber (calc_div (a, b));
else usage (argv[0]);
return 0;
}
C语言实现大数加减乘除
猜你喜欢
转载自blog.csdn.net/lgfx21/article/details/104320789
今日推荐
周排行