vlambda博客
学习文章列表

C语言 实现大数四则运算

所谓大数,就是数字非常(*100)的大,不管是int还是long long int都存储不下的数,如何进行加减乘除四则运算,这种情况在计算机的运算中还是很常见的,现将大致思路写上,并附上代码以供参考。


整体思路

首先数据必然是不能以int或者long long int存储,那么只能以字符串或者字符数组的形式存储。而且实际上,以字符数组接收数据最佳,然后把字符数组转化为int数组,再对数字进行计算。


其次,联想起我们小学二年级所学的加减乘除四则运算,我们会发现一个最基本的规律:

  • 加减乘:从右往左计算

  • 除法:从左往右计算

这就提示我们,数据需要进行一下处理,因为输入的数据是不定长的,所以我们需要把数据对齐。也就是说我们需要在加减乘,将数据倒过来,个位对个位,十分位对十分位;但是在除法中,我们只要按从左往右接收数据就可。


数据结构

int数组没有不能像字符数组那样,可以直接获取长度,所以最初想法就是在转化int数组的时候,再加上一个变量len,标记数组长度。

#define MAX 1000
struct bigNum{ int n[MAX]; int len; bigNum(){ memset(n, 0, sizeof(n)); len = 0; }};

数据处理

根据上边的思路,我们需要将char型数组转化为int型数组,而且是倒序,这样保证从个位开始对齐,方便加减乘运算,而除法只需要将char型数组转化为int型数组就可。


当然还有一些其他的工具,比如比较两个bigNum的大小,这在减法和除法上需要用到,还有除法采用的是减法思想,所以除法的数组顺序也要有个调整。

// 加减乘处理使用bigNum transfer(char str[]){ bigNum bn; bn.len = strlen(str);  int i; for(i=0; i<bn.len; i++) bn.n[i] = str[bn.len-1-i] - '0';  return bn;}// 除法处理使用bigNum transferSort(char str[]){ bigNum bn; bn.len = strlen(str);  int i; for(i=0; i<bn.len; i++) bn.n[i] = str[i] - '0';  return bn;}// 加减乘处理使用int compare(bigNum a, bigNum b){ if(a.len > b.len) return 1; else if(a.len < b.len) return -1; else{ int i; for(i=a.len-1; i>0; i--){ //高位比较  if(a.n[i] > b.n[i]) return 1; else if(a.n[i] < b.n[i]) return -1; else return 0; } }}// 除法处理使用int compareSort(bigNum a, bigNum b){ if(a.len > b.len) return 1; else if(a.len < b.len) return -1; else{ int i; for(i=0; i<a.len; i++){ //高位比较  if(a.n[i] > b.n[i]) return 1; else if(a.n[i] < b.n[i]) return -1; else return 0; } }}// 倒序,除法用void reverse(int a[], int len){ int i;  for(i=0; i<len/2; i++){ int temp = a[i]; a[i] = a[len-1-i]; a[len-1-i] = temp; } }

大数加法

bigNum add(bigNum a, bigNum b){ // a+b bigNum c; int flag = 0; int len = (a.len > b.len) ? a.len : b.len; int i; for (i=0; i<len; i++){ int temp = a.n[i] + b.n[i] + flag; flag = (temp >= 10) ? 1 : 0;  c.n[c.len++] = temp % 10;  } // 处理进位情况 if(flag != 0) c.n[c.len++] = 1;   return c; }

大数减法

bigNum sub(bigNum a, bigNum b){ // a-b 或 a+(-b)  bigNum c; int len = (a.len > b.len) ? a.len : b.len;  int i; for(i=0; i<len; i++){ if(a.n[i]<b.n[i]){  a.n[i+1]--; //借一 a.n[i] += 10; //当十  } c.n[c.len++] = a.n[i] - b.n[i];  } // 去除高位0 112-111=001,但是要保证有一位数  while(c.n[c.len-1]==0 && c.len>1) c.len--;  return c; }

大数乘法

// 高精度与低精度乘法运算,为高精度乘法运算使用bigNum sigMul(bigNum a, int b){ // 低精度 b  bigNum c; int flag = 0; int i; for(i=0; i<a.len; i++){ int temp = a.n[i]*b + flag; c.n[c.len++] = temp % 10;  flag = temp/10; } while(flag){ c.n[c.len++] = flag % 10; flag /= 10; } return c;}// 数组移位操作bigNum move(bigNum a, int index){ bigNum b = bigNum(); int i; b.len = a.len + index; for(i=0; i<a.len; i++){ b.n[i+index] = a.n[i]; } return b;}// 高精度乘法运算bigNum mul(bigNum a, bigNum b){ // 高精度 b  bigNum c = bigNum(); int i; for(i=0; i<b.len; i++){ bigNum temp = sigMul(a, b.n[i]); bigNum temp_move = move(temp,i); c = add(c, temp_move); } return c;}

大数除法

其实可以用逆序,但是当前正序思维好捋一点。减法暂时实现了除数是个位数,多位的还没来得及调试,但是考完试不太想debug,先放个坑在这里,啥时候记得补了,再回来填。欢迎大佬进行指导。

// 高精度与低精度除法运算 逆序bigNum sigDiv(bigNum a, int b, int &r){  bigNum c; c.len = a.len; int i; for(i=a.len-1; i>0; i--){ // 高位开始  r = r*10 + a.n[i]; if(r<b) c.n[i] = 0; else{ c.n[i] = r/b; r %= b; } } while(c.n[c.len-1]==0 && c.len>1) c.len--;  return c;}// 高精度除法运算bigNum div(bigNum a, bigNum b, bigNum r){ // 正序 计算大数 a/b  bigNum c; c.len = a.len;  int i;  for(i=0; i<a.len; i++){ // 高位开始  r.n[r.len++] = a.n[i]; int flag = compareSort(r, b);  if(flag == -1) c.n[i] = 0; else if(flag == 0){ c.n[i] = 1; // 无需翻转也能为0  r = sub(r, b); r.len = 0; // 结果为0,长度是1,这里需要处理,否则会多一位 } else{ // 做减法 int index = 0; while(compareSort(r, b)==1){ reverse(r.n, r.len); reverse(b.n, b.len); r = sub(r, b); reverse(r.n, r.len); index++; }  c.n[i] = index;  }  } // 处理开头 b.n-1 个0 ,循环左移 while(c.n[0]==0 && c.len>1){ int k; for(k=0; k<c.len-1; k++) c.n[k] = c.n[k+1]; c.len--; }  return c;

主函数代码

int main(){ char str1[MAX], str2[MAX]; scanf("%s%s", str1, str2); // ========================加减乘============================ // 反序,加减乘都是从右到左  //bigNum bn_str1 = transfer(str1); //bigNum bn_str2 = transfer(str2);  //bigNum bn_add = add(bn_str1, bn_str2);  //screenPrint(bn_add);   /* bigNum bn_sub; if(compare(bn_str1,n_str2) == 1){ // a>b bn_sub = sub(bn_str1, bn_str2);  }else if(compare(bn_str1, bn_str2) == -1){ // a<b bn_sub = sub(bn_str2, bn_str1);  printf("-");  } else{ // a=b  bn_sub = sub(bn_str1, bn_str2); } screenPrint(bn_sub);  */  // ========================除法============================  // 正序,除是从左到右  bigNum bn_str1 = transferSort(str1); bigNum bn_str2 = transferSort(str2);  //reverse(bn_str1.n, bn_str1.len); //print(bn_str1);   bigNum bn_r = bigNum(); if(compareSort(bn_str1, bn_str2) == 1){ // a>b bigNum bn_div = div(bn_str1, bn_str2, bn_r); print(bn_div); }  else if(compareSort(bn_str1, bn_str2) == -1) printf("0"); // a<b else printf("1"); // a=b   return 0;

不太想码字了,刚考完密码学第一次编程考试,人生啊,就是如此艰难。溜了溜了,睡觉。