题目:大整数计算

* 背景介绍:
大整数一般指超过十尾的十进制整数,假定不超过五十位。这类大整数在C语言系统中因超界溢出而不能直接表达或计算。
* 实现方法:
以字符串形式输入、输出和存放大整数,计算时可以将字符串中的每一位数字转换成相应的数值进行运算。
* 功能要求:
主函数输入两个大整数,并提供功能菜单供用户选择,用户可以选择调用各个运算功能,对两个大整数进行相应的运算,并输出结果。也可以选择继续或退出程序。
功能:1. 加法 2. 减法 3. 乘法
* 代码实现: #include <stdio.h> #include <stdlib.h> #include <math.h> #include <
string.h> #include <conio.h> #define MAX 51 //题目假设大整数最高为50位,所以取长度为MAX(51)的字符数组
void format(int *a) //升位: 低位除10剩余数,高位加商;比如十位的13,变成百位加1和十位剩3 { int p; for(p = 1;
p< a[0] || a[p] >= 10; p++) { if (p >= a[0]) a[p+1] = 0; a[p+1] += (a[p] / 10);
//高位加上除10运算的商 a[p] = a[p] % 10; //低位等于除10运算的余数 } if (p >= a[0]) a[0] = p; } void
add(int *a,int *b,int *c) { int len,i; if (a[0] < b[0]) len=a[0]; else len=b[0];
for(i = 1; i <= len; i++) { c[i] = a[i] + b[i]; } if (len < a[0]) { for( ; i <=
a[0]; i++) { c[i] = a[i]; } c[0] = a[0]; } else { for( ; i <= b[0]; i++) { c[i]
= b[i]; } c[0] = b[0]; } format(c); } void commaltiply (int *a, int x, int *b) {
int i; for(i = 1; i <= a[0]; i++) { b[i] = a[i] * x; } b[0] = a[0]; format(b); }
void matiply(int *a,int *b,int *c) { int i,temp[MAX],j; commaltiply(a, b[1], c);
for(i = 2; i <= b[0]; i++) { if(b[i] == 0) { c[0]++; for (j = c[0]; j > 1; j--)
c[1] = 0; } else { commaltiply(a, b[i], temp); for(j = 1; j < i; j++)
commaltiply(temp, 10, temp); add(c, temp, c); } } } void format1(int *a) //降位:
高位减1 补到 低位成10;比如百位的1相当于十位的10 { int i; for(i = 1; i <= a[0]; i++) if(a[i] < 0) {
a[i] += 10; a[i+1] -= 1; } } void sub_1(int *a,int *b,int *c) //默认形参a比b长的减法运算 {
int i; for(i = 1; i <= b[0]; i++) c[i] = a[i] - b[i]; if(a[0] != b[0]) { //初始时
i = b[0],从b[0]开始+1,最终加到a[0] for ( ; i <= a[0]; i++) c[i] = a[i]; } c[0] = a[0];
format1(c); i = c[0]; //先让i暂存运算结果的位数(长度) while(1) { if(c[i] == 0)
//从高位开始检查,如果高位数字为0,则 位数-1 i--; else //当检查到某较高位数不为0,则退出while循环 break; } c[0] = i;
//c[0] 存储检查后的位数 } void sub(int *a, int *b, int *c) //减法 { int i, flag = 0;
//flag用来标记 两个大整数是否相等的 for(i = 1; i <= a[0]; i++) //a[0] 是 大整数的长度 if(a[i] != b[i]
) //两个大整数只要有一位数字不相等,则flag = 1 { flag = 1; break; } if(flag == 0)
//如果两个大整数完全相等,则flag不变还是0 则计算结果为0 { c[0] = 0; return; } flag = 0; //此时flag用来标记
a和b运算减法运算的情况 if(a[0] == b[0]) //如果两个大整数的长度相同 { for(i = a[0]; i > 0; i--)
//从最高位开始比较 { if(a[i] > b[i]) //如果a的最高位数字比b的大 { sub_1(a,b,c); //正常执行减法运算 break; }
if(a[i] < b[i]) //如果a的最高位数字比b的小,b减a,flag=1 { flag = 1; sub_1(b,a,c); break; } }
} if(a[0] > b[0]) //如果a,b的长度不等,且a比b长,直接计算 { sub_1(a,b,c); } else if (a[0] < b[0]
) //如果a,b的长度不等,且a比b短,执行b减a { flag = 1; sub_1(b,a,c); } if (flag)
//执行b减a运算的时候结果应该取相反数 c[0] = -c[0]; else c[0] = c[0]; } void read_in(int *a)
//读入长整数 { int len, i; int flag = 0; // flag用来标记负数的存在,正数记0,负数记1 int flag_error =
0; char s[MAX]; //如果读入的是负长整数,则字符数组的第一个位置要存储负号 //而且长整数的最大位数为50位,因此需要长度为51的字符数组
//正长整数则不用担心这个问题 while(1) { scanf("%s",s); len = strlen(s); if (s[0] == '-') flag
= 1; //标记负数 for(i = len-flag; i >= 1; i--) //倒序存储 { if ((s[len-i]-'0') < 0||(s[
len-i]-'0') > 9) { printf("\t\t\t 第%d位输入错误,按任意键重新输入!",len-i+1); getch();
flag_error++; break; //某位错误,错误标记记1,不再检查其他位数,跳出for循环,检查flag_error } else a[i] = s
[len-i] - '0'; /* 如果第i位没错,把该位的数字字符转换成数字存入a[]数组中 * s[len-i]-'0'是利用
数字字符的ASCII码和数字本身数值大小的关系 * 来实现 字符转换成数字 的功能 */ } // end for if(flag_error)
continue; //continue:不执行后面的语句,重新开始一次while循环 if (flag) a[0] = -(len-1); else a[0]
= len; break; } // end while } void print(int *a) { int i; if (a[0] < 0) {
printf("-"); } if (a[0] == 0) { printf("0"); return; } for(i = abs(a[0]); i >= 1
; i--) //倒序输出 printf("%d",a[i]); printf("\n"); } char menu() //功能菜单 { char ans;
// answer的简写,用于存储用户输入的回答 while(1) { printf("\n\n\n"); printf(
"\t\t\t\t————————————————\n"); printf("\t\t\t\t| > 长整数计算器 < |\n"); printf(
"\t\t\t\t| |\n"); printf("\t\t\t\t| 1.大整数的加法 |\n"); printf("\t\t\t\t| 2.大整数的减法
|\n"); printf("\t\t\t\t| 3.大整数的乘法 |\n"); printf("\t\t\t\t| 4.退出 |\n"); printf(
"\t\t\t\t| |\n"); printf("\t\t\t\t————————————————\n"); printf("\n\n\n\t\t\t
请选择功能(1-4): "); ans = getchar(); if(ans == '1'||ans == '2'||ans == '3'||ans ==
'4') break; else { getch(); printf("\n\t\t\t  输入错误!按任意键重新输入!!!!"); getch();
system("cls"); } } return ans; } int main() { int a[MAX],b[MAX],c[MAX]; //
a存储第一个长整数,b存储第二个,c存储运算结果 char ans; // answer的简写,用于存储用户输入的回答 while(1) { ans =
menu(); if(ans == '4') return 0; //先判断是否要退出 printf("\n\t\t\t  请输入大整数A: ");
read_in(a); printf("\n\t\t\t  请输入大整数B: "); read_in(b); if (ans == '1') { if (a[0
] < 0 && b[0] < 0) { a[0] = -a[0]; b[0] = -b[0]; add(a,b,c); c[0] = -c[0]; a[0]
= -a[0]; b[0] = -b[0]; } if (a[0] > 0 && b[0] < 0) { b[0] = -b[0]; sub(a,b,c); b
[0] = -b[0]; } else if (a[0] > 0 && b[0] > 0) { add(a,b,c); } else if (a[0] < 0
&& b[0] > 0) { a[0] = -a[0]; sub(b,a,c); a[0] = -a[0]; } printf("\n\t\t\t A = ")
; print(a); printf("\n\t\t\t B = "); print(b); printf("\n\t\t\t C = A+B = ");
print(c); } // end if(rn=='1') else if (ans == '2') { if (a[0] < 0 && b[0] < 0)
{ a[0] = -a[0]; b[0] = -b[0]; sub(b,a,c); a[0] = -a[0]; b[0] = -b[0]; } if (a[0]
< 0 && b[0] > 0) { a[0] = -a[0]; add(a,b,c); a[0] = -a[0]; c[0] = -c[0]; } if (a
[0] > 0 && b[0] < 0) { b[0] = -b[0]; add(a,b,c); b[0] = -b[0]; } if (a[0] > 0 &&
b[0] > 0) sub(a,b,c); printf("\n\t\t\t A = "); print(a); printf("\n\t\t\t B = "
); print(b); printf("\n\t\t\t C = A-B = "); print(c); } // end if(rn=='2') else
if (ans == '3') { if (a[0] < 0 && b[0] > 0) { a[0] = -a[0]; matiply(a,b,c); a[0]
= -a[0]; c[0] = -c[0]; } else if (a[0] > 0 && b[0] < 0) { b[0] = -b[0]; matiply(
a,b,c); b[0] = -b[0]; c[0] = -c[0]; } else if (a[0] < 0 && b[0] < 0) { a[0] = -a
[0]; b[0] = -b[0]; matiply(a,b,c); a[0] = -a[0]; b[0] = -b[0]; } else matiply(a,
b,c); printf("\n\t\t\t A = "); print(a); printf("\n\t\t\t B = "); print(b);
printf("\n\t\t\t C = A*B = "); print(c); } // end if(rn=='3') while(1) { printf(
"\n\t\t\t 是否继续计算?(y/n): "); getchar(); ans = getchar(); if(ans == 'y' || ans ==
'Y') { system("cls"); getchar(); break; } else return 0; } // end inside while }
// end outside while } // end main
*
代码分析:

* 关于sub_1与sub函数关系:
sub_1就像一个机器一样,它不管你怎么投入的数字,他只会按照固定的顺序(第1个减第2个的结果存入第3个)来计算,产出结果,
而sub就有点“智能”,根据a和b不同的情况,来调整投入sub_1机器的数字顺序(abc还是bac)
总结:sub是“操作机器的人”,sub_1是“机器”
*
运行结果:

* 存在的缺陷:
* 健壮性较弱,例如菜单测试用例为"b2"时,运行结果如下:

* 错误分析:

第一个"b"被当作菜单的输入,去匹配功能选项(1-4),因为是错误输入调用了清屏函数,而"2"留在缓存区被当作下一次的菜单输入匹配到功能2,因此执行了长整数减法。
类似的输入测试用例还有"1111abcn"等等

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信