大数四则运算的数据流程图
文字说明数据的流动方向(这里仅仅举例当选择大数加法(i==1)和 大数乘法(i==3)
大数加法数据流向:
首先:::键盘输入 1 ,选择大数加法
然后:::系统提示输入被加数(num1)和加数(num2)
接着:::判断num1和num2的符号是否同号
若同号,则常规处理将num1和num2调用大数加法的核心函数。
若异号,则两者之间只有一个负数,此时两数相加相当于一个正数减另一个正数,所以在这里我们调用大数减法的核心函数。
最后输出,然后回到菜单,再次请求选择四则运算中的编号,或者退出。
大数乘法数据流向:
首先:::键盘输入 1 ,选择大数乘法
然后:::系统提示输入被乘数(num1)和乘数(num2)
接着:::判断num1和num2的符号是否同号
若同号,则调用大数乘法的核心函数
反之,调用用大数乘法的核心函数之前 先输出一个负号,再输出结果。
其他的两种运算与上面两种差不多,就不再做详细介绍。
大数菜单界面如下图:
运行举例之大数加法运算
本程序的大数加法运算并不要求被加数和前加数都为大于零的正数,两个或者一个数据都可以相加。
举例:333333333333333333+(-111111111111111111) = 222222222222222222
注:本程序的大数四则运算,每种运算都可以用负数来进行运算。
大数加法运算举例如图
本程序中最有有趣的是每种运算的算法,感兴趣的同学可以去研究一下。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<malloc.h>
#define MAXLEN 10000
//全局变量
int g[MAXLEN];
//加法函数声明
void addition_of_large_numbers(char aa[],char bb[]);//大数加法的核心函数
void Addition_Symbol_Judge();//被加数 加 加数的结果的正负号判断
//减法函数声明
void subtraction_size_judge(char a[],char b[]); //被减数与减数的大小比较
void subtraction_core_algorithm(char x[],char y[],int max_len);//大数减法的核心函数
void subtraction_Symbol_Judge();//被除数 除 除数的结果的正负号判断
//乘法函数声明
void multiplication_of_lager_numbers(const char *num1, const char *num2);//大数乘法的核心函数
void multiplication_Symbol_Judge();//被乘数 乘 乘数的结果的正负号判断
//除法函数声明
void Sub_Operation(char s1[],char s2[],int len2);//(1)大数除法的核心函数
void Division_Of_Large_Numbers(char s1[],char s2[]);//(2)大数除法的核心函数
void Division_Symbol_Judge();//被除数 除 除数的结果的正负号判断
//主界面函数声明
void mainInterface();//界面函数
/**********************************************大数四则运算界面开始段*************************************************************/
void mainInterface()//界面函数
{
int yourchoice;
printf("\n");
printf(" -----------------欢迎使用大数四则运算------------\n");
printf("\n 菜 单 选 择 \n\n");
printf(" 1.大数加法运算\n");
printf(" 2.大数减法运算\n");
printf(" 3.大数乘法运算\n");
printf(" 4.大数除法运算\n");
printf(" 5.退出! \n");
printf("\n");
printf(" --------------------------------------------------\n");
printf("\n 请输入您的选择:");
scanf("%d",&yourchoice);
while(!(yourchoice==1||yourchoice==2||yourchoice==3||yourchoice==4||yourchoice==5))
{
printf(" 输入选择不明确,请重输:");
scanf("%d",&yourchoice);
}
while(1)
{
switch(yourchoice)
{
case 1:
Addition_Symbol_Judge();
break;
case 2:
subtraction_Symbol_Judge();
break;
case 3:
multiplication_Symbol_Judge();
break;
case 4:
Division_Symbol_Judge();
break;
case 5:
//system("cls");
printf("\n");
printf(" 欢迎下次使用。");
printf("\n\n\n\n\n\n");//99999999999999999999//10000000000000000000
exit(0);
}
printf("\n");
system("pause");
system("cls");
printf("\n");
printf(" -----------------欢迎使用大数四则运算------------\n");
printf("\n 菜 单 选 择 \n\n");
printf(" 1.大数加法运算\n");
printf(" 2.大数减法运算\n");
printf(" 3.大数乘法运算\n");
printf(" 4.大数除法运算\n");
printf(" 5.退出! \n");
printf("\n");
printf(" --------------------------------------------------\n");
printf("\n 请输入您的选择:");
scanf("%d",&yourchoice);
while(!(yourchoice==1||yourchoice==2||yourchoice==3||yourchoice==4||yourchoice==5))
{
printf(" 输入选择不明确,请重输:");
scanf("%d",&yourchoice);
}
}
}
/**********************************************大数四则运算界面结束段*************************************************************/
int main(){mainInterface();}//主函数
/**********************************************大数加法代码开始段*****************************************************************/
void addition_of_large_numbers(char aa[],char bb[])//大数加法的核心函数
{
int i,up,tmp;
char a[MAXLEN+1]= {0},b[MAXLEN+1]={0};//为什么要加1,是当你的ab数组的个数为MAXLEN时,留一个地方给你进位;等于零我可以理解。
for(tmp=0,i=strlen(aa)-1;i>=0;i--)//strlen(buffer)的长度是你为a输入的 数字字符串长度。
a[tmp++] = aa[i]-'0';//a数组中储存的是阿拉伯数字,并不是字符 ,a数组中的数字已经反向存储了;
for(tmp=0,i=strlen(bb)-1;i>=0;i--)
b[tmp++] = bb[i]-'0';
for(up=0,i=0;i<=MAXLEN;i++){
tmp = a[i]+b[i]+up;//按照小学竖式算法。两者相加,并且加上进位数
a[i] = tmp%10;//这里%10的目的是为了得到tmp数的个位数值,而不是把tmp数的十位数值给a[i],因为输出时是倒序输出;
up=tmp/10;//记录进位数
}
for(i=MAXLEN;i>=0;i--)//从数组最后一个位置开始查找。
{
if(a[i]!=0)//查找不为零的数,当a数组的长度大于b数组的长度时或者反过来,前者得到的结果要么与a数组的长度相同,要么比a大。
{
for(i;i>=0;i--)
printf("%d",a[i]); //******a本来是char型数组,可到最后你用%d十进制输出,那你不应该输出的时字符的ascll码值吗?
}
}
}
void Addition_Symbol_Judge()//被加数 加 加数的结果的正负号判断,(里面包含了被加数和加数的输入)
{
char a[MAXLEN+1] = {0},b[MAXLEN+1] = {0};
printf("\n");
printf(" 请输入被加数:");
scanf(" %s",a);
printf(" 请输入加数:");
scanf(" %s",b);
printf("\n");
printf("最终结果为:");
if(a[0]>='0'&&a[0]<='9'&&b[0]>='0'&&b[0]<='9')//a不能等于0;
{
printf("%s + %s = ",a,b);
addition_of_large_numbers(a,b);
}
else if(a[0]>='0'&&a[0]<='9'&&b[0]=='-')
{
//printf(" //调用减法函数;并且是a-b;");
printf("%s + (%s) = ",a,b);
for(int i=0;i<strlen(b);i++)//这一步是为了把b的负号去掉,并且在最后加上"\0";
b[i] = b[i+1];
subtraction_size_judge(a,b);
}
else if(a[0]=='-'&&b[0]>='0'&&b[0]<='9')
{
//printf("//调用减法函数;并且是b-a;");
printf("(%s) + %s = ",a,b);
for(int i=0;i<strlen(a);i++)//这一步是为了把a的负号去掉,并且在最后加上"\0";
a[i] = a[i+1];
subtraction_size_judge(b,a);
}
else
{
printf("(%s) + (%s) = ",a,b);
for(int i=0;i<strlen(b);i++)//这一步是为了把b的负号去掉,并且在最后加上"\0";
b[i] = b[i+1];
for(int i=0;i<strlen(a);i++)//这一步是为了把a的负号去掉,并且在最后加上"\0";
a[i] = a[i+1];
printf("-");
addition_of_large_numbers(a,b);
}
}
/**********************************************大数加法代码结束段*****************************************************************/
/**********************************************大数减法代码开始段*****************************************************************/
void subtraction_size_judge(char a[],char b[])//被减数与减数的大小比较
{
char x[MAXLEN+1] = {0},y[MAXLEN+1] = {0};
int len1,len2;
int i,j=0,k=0;
len1=strlen(a); //两个数组的长度。
len2=strlen(b);
for(i=len1-1,j=0;i>=0;i--)//将两个字符串中的"*****字符转化为数字****",并倒序储存到数组中,即字符串为123456,则数组为654321
x[j++]=a[i]-'0';
for(i=len2-1,k=0;i>=0;i--)
y[k++]=b[i]-'0';
if(len1>len2) //若减数长度 > 被减数,正常减
subtraction_core_algorithm(x,y,len1);
else if(len1<len2) //若减数长度 < 被减数,被减数 减 减数
{
printf("-");
subtraction_core_algorithm(y,x,len2);
}
else if(len1==len2&&strcmp(a,b)==0)
{
subtraction_core_algorithm(a,b,len1);
}
else //若减数长度 == 被减数,判断两个数的大小
{
for(i=len1-1;i>=0;i--)//判断每一位两个数的大小
{
if(x[i]==y[i])
continue;
if(x[i]>y[i])//即减数大
{
subtraction_core_algorithm(x,y,len1);
break;
}
if(x[i]<y[i])//即被减数大
{
printf("-");
subtraction_core_algorithm(y,x,len1);
break;
}
}
}
}
void subtraction_core_algorithm(char x[],char y[],int max_len)//大数减法的核心函数
{
int i,j;
char z[MAXLEN+1] = {0};
/********************减数的的核心代码**************/
for(i=0;i<max_len;i++)
/*
**i<len是为什么,len是len1和len2中最大的一个;
**两个数的位数只有相等和一大一小,大的在上面,小的在下面;
**i<len是为了确保长的len能完全减完;
**而且它不像大数加法要一个进位,所以它不要MAXLEN+1;
*/
{
if(x[i]>=y[i])//如果x[i]>=y[i],不用向前一位借1,可直接减
z[i]=x[i]-y[i];
else //如果x[i]<y[i],向前一位借1,同时前一位应减1
{
z[i]=x[i]+10-y[i]; //6-8要借位,所以6+10 - 8 =8;存入z数组;
x[i+1]=x[i+1]-1; //借位要减1;
}
}
/********************减数结果修饰**************/
for(i=max_len-1;i>0;i--)//删除后缀0 i= len-1是因为得到的z数组中存储的结果长度是等于len的(包括他们的前缀零);
{
if(z[i]==0)//因为不可能是这样0001200的结果;所以你可以为后面输出没有零做准备;
max_len--;
else
break;
}
/********************减数结果的输出**************/
for(i=max_len-1;i>=0;i--) //倒序输出数组
printf("%d",z[i]);
printf("\n");
}
void subtraction_Symbol_Judge()//被减数 减 减数的结果的正负号判断,(里面包含了被减数和减数的输入)
{
char a[MAXLEN+1]= {0},b[MAXLEN+1] = {0};//通过字符串对大数进行输入并储存 我想给他来一个MAXLEN+1的玩意
printf("\n");
printf(" 请输入被减数:");
scanf(" %s",a);
printf(" 请输入减数:");
scanf(" %s",b);
printf("\n");
printf(" 最终结果为:");
if(a[0]>='0'&&a[0]<='9'&&b[0]>='0'&&b[0]<='9')
{
printf("%s - %s = ",a,b);
subtraction_size_judge(a,b);
}
else if(a[0]>='0'&&a[0]<='9'&&b[0]=='-')
{
printf("%s - (%s) = ",a,b);
for(int i=0;i<strlen(b);i++)
b[i] = b[i+1];
addition_of_large_numbers(a,b);
}
else if(a[0]=='-'&&b[0]>='0'&&b[0]<='9')
{
printf("(%s) - %s = ",a,b);
for(int i=0;i<strlen(a);i++)//这一步是为了把a的负号去掉,并且在最后加上"\0";
a[i] = a[i+1];
printf("-");
addition_of_large_numbers(a,b);
}
else
{
printf("(%s) - (%s) = ",a,b);
for(int i=0;i<strlen(b);i++)//这一步是为了把b的负号去掉,并且在最后加上"\0";
b[i] = b[i+1];
for(int i=0;i<strlen(a);i++)//这一步是为了把a的负号去掉,并且在最后加上"\0";
a[i] = a[i+1];
subtraction_size_judge(b,a);
}
}
/**********************************************大数减法代码结束段*****************************************************************/
/**********************************************大数乘法法代码开始段***************************************************************/
void multiplication_of_lager_numbers(const char *num1, const char *num2)//大数乘法的核心函数
{
int change = 0;
int *result = NULL; //用来保存最终结果
int num1Len = strlen(num1); //num1的长度
int num2Len = strlen(num2); //num2的长度
int resultLen; //结果的最大长度
int i, j; //循环计数器
resultLen = num1Len + num2Len; //结果长度最大为num1长度和num2长度之和
//初始化result为0
result = (int *)malloc((resultLen+1)*sizeof(int));
memset(result, 0, (resultLen+1)*sizeof(int));
/*memset函数的功能是:将指针变量 s 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。s 是 void* 型的指针变量,
所以它可以为任何类型的数据进行初始化。*/
result[0] = resultLen; //result的第一位是用来保存result的长度的。
/* num1乘以num2,由于这里采用先不进位的算法,所以算法是按从左到右
* 按顺序来乘,然后将每位的结果保存到result的每一位中,循环一次
* reult就从下一位开始求和。如下:(左边为正常算法,右边为本程序算法)
*
* 54321 | 54321
* × 123 | × 123
* ------- | --------
* 162963 | 54321
* 108642 | 108642
* 54321 | 162963
* -------- | ---------
* 6681483 | 6681483
*
* */
for(j = 0; j < num2Len; j++)
{
for(i = 0; i < num1Len; i++)
{
/* result第一位是用来保存result长度的,而第二位是保存结果最后的进位的
* 没有进位,则result[1]为0,所以每位相乘之和是从第三位(即result[2])
* 开始。这里是本程序的比较巧妙的地方,需要仔细想想。
* */
result[i+j+2] += (num1[i]-'0') * (num2[j]-'0');
}
}
/* 这个循环用来处理进位的,所以要从result的最后一位一直处理到首位。
* 要注意result的总长度是resultLen+1,有一位是保存result的长度,而
* C语言下标是从0开始,所以result的最后一位的下标就是resultLen,而
* 第一位就是1。*/
for(i = resultLen; i > 1; i--)
{
result[i-1] += result[i]/10;
result[i] = result[i]%10;
}
for(i = 1; i <= result[0]; i++)
{
/*
*输出从下标1开始,result[1]是用来储存进位数的,如果result[1]为0且result[2]不为0,则输出result[2]以后的数。
* 如果result[1]为0且result[2]为0,则我们的结果为0,直接输出结果0且结束循环输出 。
*/
if(result[i] != 0) //这一步用来去掉前导0,第一位为0跳过不输出
change = 1;
if(!change)
{
if(i > 1) //这一步用来判断结果是否为0,
{ //如果结果第二位还是0,就判断为0
printf("0");
break;
}
continue;
}
printf("%d", result[i]);
}
}
void multiplication_Symbol_Judge()//被乘数 乘 乘数的结果的正负号判断,(里面包含了被乘数和乘数的输入)
{
char num1[10000] = {'\0'}, num2[10000] = {'\0'}; //这一步是啥意思 ,给num1[0]赋值\0,而num1[1]~num1[99] 将都赋值为\0;
printf("\n");
printf(" 请输入被乘数:");
scanf(" %s",num1);
printf(" 请输入乘数:");
scanf(" %s",num2);
printf("\n");
printf(" 最终结果为:");
if((num1[0]>'0'&&num1[0]<='9'&&num2[0]>'0'&&num2[0]<='9')||(num1[0]=='-'&&num2[0]=='-'))
{
if(num1[0]=='-'&&num2[0]=='-')
{
printf("(%s) * (%s) = ",num1,num2);
for(int i=0;i<strlen(num2);i++)//这一步是为了把num2的负号去掉,并且在最后加上"\0";
num2[i] = num2[i+1];
for(int i=0;i<strlen(num1);i++)//这一步是为了把num1的负号去掉,并且在最后加上"\0";
num1[i] = num1[i+1];
multiplication_of_lager_numbers(num1, num2);
}else
{
printf("%s * %s = ",num1,num2);
multiplication_of_lager_numbers(num1, num2);
}
}
else if((num1[0]>'0'&&num1[0]<='9'&&num2[0]=='-')||(num2[0]>='0'&&num2[0]<='9'&&num1[0]=='-'))
{
if(num2[0]=='-')
{
printf("%s * (%s) = ",num1,num2);
for(int i=0;i<strlen(num2);i++)//这一步是为了把num2的负号去掉,并且在最后加上"\0";
num2[i] = num2[i+1];
printf("-");
multiplication_of_lager_numbers(num1, num2);
}else
{
printf("(%s) * %s = ",num1,num2);
for(int i=0;i<strlen(num1);i++)//这一步是为了把num2的负号去掉,并且在最后加上"\0";
num1[i] = num1[i+1];
printf("-");
multiplication_of_lager_numbers(num1, num2);
}
}
}
/**********************************************大数乘法法代码结束段***************************************************************/
/**********************************************大数除法法代码开始段***************************************************************/
void Sub_Operation(char s1[],char s2[],int len2)//(1)大数除法的核心函数
{
int i=0,j;
while(1)
{
if(s1[i]=='0') i++;
else
{
j=i;
break;
}
}
for(; i<len2; i++)//数字位对位相减
s1[i]=s1[i]-s2[i]+'0';//最终s1中存放的是余数
for(i=len2-1; i>j; i--)//处理s1中的负数
if(s1[i]<'0')
{
s1[i]+=10;;
s1[i-1]--;
}
/*
1、不停的用被除数位首(从除数第一位开始与被除数位数相等的那几位)减去除数,直到被除数位首小于除数
2、将次数保存在数组里,然后在被除数的的前面添一个0继续相减
3、按照以上方法继续运算,直到被除数位尾(从被除数最后一位开始与除数位数相等的那几位)相减之后即可结束。
例子如下:被除数446,除数23
————————————————
版权声明:本文为CSDN博主「-纸短情长」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/l_liangkk/article/details/52022495
举例:446%23
446
-23
-------
216
此时可以看见21比23小,然后在23前面加零 则
216
-023
-------
2(-1)3
此时可以看见有 "负数" 出现了 经过处理后
193
-023
------
170
............. 一直重复 直到 078的出现
078
-023
--------
为什么提及078
因为这体现了 while(1)代码的作用。
j=i(i = 0) 而 j在 "处理负数" 时出现
这会导致 程序只会检查 7 和 8 ,并不会检查 0
*/
}
void Division_Of_Large_Numbers(char s1[],char s2[])//(2)大数除法的核心函数
{
int i,j,k,len1,len2;//num1,num2的长度
len1=strlen(s1);//获取num1,num2的长度
len2=strlen(s2);
if(len1<len2||len1==len2&&strcmp(s1,s2)<0)//当被除数小于除数的特殊情况
{
printf("0 余数 = ");//求余数
for(i=0; i<len1; i++)
printf("%d",s1[i]-'0');
printf("\n");
}else {
k=0;
while(1)
{
g[k]=0;
while(strcmp(s1,s2)>=0)//一直进行减法,直到不能减为止
{
Sub_Operation(s1,s2,len2);
g[k]++;//它的最终结果是 商
//它从 下标0 开始记录
//当 K++ 时,意味着 break(跳出) while(1) 或者 除数要加零
//同时商的数组也会向后移一位 再次记录减的次数
}
k++;
if(len1==len2) break;
for(i=len2-1; i>=0; i--) //在s2前面补0,以便进行减法运算
{s2[i+1]=s2[i];}
s2[0]='0';//在前面加零
len2++;//s2 的字符串加长
s2[len2]='\0';//strcmp()函数遇到字符'\0'结束
}
//输出商
i=0;
while(g[i]==0) i++;//去除前导0
for(; i<k; i++)//输出商
{printf("%d",g[i]);}
//输出余数
printf(" 余数 = ");
j=0;//求余数
while(s1[j]=='0')
{j++;}
if(j==len1)//如果储存余数 s1 中的字符都为'0',那么s1中 '0' 的个数与它本身开始的长度相同,则余数为零
{
printf("0\n");
}
else {
for(; j<len1; j++)
printf("%d",s1[j]-'0');
}
}
// }
}
void Division_Symbol_Judge()//被除数 除 除数的结果的正负号判断,(里面包含了被除数和除数的输入)
{
int len1,len2;//num1,num2的长度
char num1[MAXLEN],num2[MAXLEN];
printf("\n");
printf(" 请输入被除数:");
scanf(" %s",num1);
printf(" 请输入除数:");
scanf(" %s",num2);
while(num2[0] == '0'){
printf(" 除数不能为 \"0\"!\n");
printf(" 请重新输入:");
scanf(" %s",num2);
}
printf("\n");
printf(" 最终结果为:");
len1=strlen(num1);//获取num1,num2的长度
len2=strlen(num2);
if((num1[0]>'0'&&num1[0]<='9'&&num2[0]>'0'&&num2[0]<='9')// 如果被除数和除数的 "结果" 为 正数
||(num1[0]=='-'&&num2[0]=='-'))
{
if(num1[0]=='-'&&num2[0]=='-')//如果被除数和除数都为 负数
{
printf("(%s) %% (%s) = ",num1,num2);
for(int i=0;i<strlen(num2);i++)//这一步是为了把num2的负号去掉,并且在最后加上"\0";
{num2[i] = num2[i+1];}
for(int i=0;i<strlen(num1);i++)//这一步是为了把num1的负号去掉,并且在最后加上"\0";
{num1[i] = num1[i+1];}
Division_Of_Large_Numbers(num1, num2);//调用核心函数
}else
{
printf("%s %% %s = ",num1,num2);
Division_Of_Large_Numbers(num1, num2);
}
}else if((num1[0]>'0'&&num1[0]<='9'&&num2[0]=='-')//如果被除数或者除数中有一个为 负数
||(num2[0]>='0'&&num2[0]<='9'&&num1[0]=='-'))
{
if(num2[0]=='-')//如果除数为 负数
{
printf("%s %% (%s) = ",num1,num2);
for(int i=0;i<strlen(num2);i++)//这一步是为了把num2的负号去掉,并且在最后加上"\0";
{num2[i] = num2[i+1]; }
if(len1+1<len2||len1+1==len2&&strcmp(num1,num2)<0)//如果num1小于num2,则商为零,零前面不用 负号
{
Division_Of_Large_Numbers(num1, num2);
} else { //如果商不为零,则前面可以用 负号
printf("-");
Division_Of_Large_Numbers(num1, num2);
}
}else// 如果被除数为 负数
{
printf("(%s) %% %s = ",num1,num2);
for(int i=0;i<strlen(num1);i++)//这一步是为了把num1的负号去掉,并且在最后加上"\0";
num1[i] = num1[i+1];
if(len1<len2+1||len1==len2+1&&strcmp(num1,num2)<0)//如果num1小于num2,则商为零,零前面不用 负号
{
Division_Of_Large_Numbers(num1, num2);
} else { //如果商不为零,则前面可以用 负号
printf("-");
Division_Of_Large_Numbers(num1, num2);
}
}
}
}
/**********************************************大数除法法代码结束段***************************************************************/