大数加法(加数可为负数)
·分析:
大数加法有如下几种情况:
1.两数同号
(1)同正:如,s1=11,s2=22;s1=0,s2=0
(2)同负:如,s1=-11,s2=-22
2.两数异号
(1)正数加负数:如,s1=11,s2=-9
1)s1的长度大于s2绝对值的长度:如,s1=11,s2=-9
2)s1和s2绝对值的长度相等但s1大于等于s2的绝对值:s1=106,s2=-104;s1=11,s2=-11
3)s1的长度小于s2绝对值的长度:如,s1=9,s2=-11
2)s1和s2绝对值的长度相等但s1小于s2的绝对值:s1=104,s2=-106
(2)负数加正数:如,s1=-9,s2=11
位置转换可变换为“正数加负数”形式
处理:
首先,将大数以字符串形式输入
其次,判断s1与s2符号,调用不同函数处理
(1)同号:调用Plus函数
1)如果同正,设置标志结果符号的flag为0,将两个字符串转化为数组形式倒序存储
2)如果同负,设置标志结果符号的flag为1,将两个字符串转化为数组形式倒序存储,但不存储两字符串的第0位(因为第0位为负号)
3)将两数组对应位相加,位数满10进1
4)根据flag值输出结果的符号
5)判断最高位是否为0,输出结果数组
(2)异号:调用Minus函数
1)调用函数时以正数-负数顺序传递实参给形参,即s1为正数,s2为负数
2)将两个字符串转化为数组形式倒序存储,但不存储s2字符串的第0位(因为s2[0]为负号)
3)判断结果符号,根据两数大小,有两种情况:
1)s1的长度大于s2的长度或s1和s2长度相等但s1大于等于s2,即:
len1>(len2-1) 或 len1==(len2-1),s1>=s2 做num1-num2,设置flag=0,标志得正数
2)s1的长度小于s2的长度或s1和s2长度相等但s1小于s2,即:
len1<(len2-1)或 len1==(len2-1),s1<s2 做num2-num1,设置flag=1,标志得负数
3)调用Minus_show函数
- 对传进来的num1-num2或num2-num1做减法计算
- 将两数组对应位相减,位数不够减向前借1
- 根据flag值输出结果的符号
- 判断最高位是否为0,输出结果数组
实现:
#include<stdio.h>
#include<string.h>
char s1[10005],s2[10005],s3[10005];
int num1[10005],num2[10005];
int len1,len2,i,j;
//当s1与s2同号,利用flag标志结果的符号(0为正,1为负)
void Plus(int flag)
{
len1=strlen(s1);
len2=strlen(s2);
for(i=len1-1,j=0; i>=0 ; i--)
{
num1[j]=s1[i]-48;
j++;
if(i==flag) break; //如果s1与s2同负,flag=1,则不进行下一次循环赋值字符串第0位
}
for(i=len2-1,j=0; i>=0 ; i--)
{
num2[j]=s2[i]-48;
j++;
if(i==flag) break; //如果s1与s2同负,flag=1,则不进行下一次循环赋值字符串第0位
}
//计算两字符串长度最大值作为和的长度
int len;
if(flag==0) len=len2>len1?len2:len1;
else len=len2>len1?(len2-1):(len1-1); //如果s1与s2同负,flag=1,len值应为长度减1
//进行加计算及进位
for(i=0; i<len; i++)
{
num1[i]+=num2[i];
if(num1[i]>9)
{
num1[i+1]+=1;
num1[i]-=10;
}
}
//输出符号位
if(flag==1) printf("-"); //如果s1与s2同负,flag=1,结果的符号位为负
//输出结果
if(num1[i]) //最高位进位
{
for(j=i; j>=0; j--)
printf("%d",num1[j]);
printf("\n");
}
else //最高位未进位
{
for(j=i-1; j>=0; j--)
printf("%d",num1[j]);
printf("\n");
}
}
//对异号的s1和s2处理成“大数-小数”形式后调用该函数进行减计算并显示,利用flag标志结果的符号(0为正,1为负)
void Minus_show(int flag,int len,int num1[],int num2[])
{
//进行减计算及借位
for(i=0; i<len; i++)
{
if(num1[i]>=num2[i])
{
num1[i]-=num2[i];
}
else
{
num1[i]=num1[i]+10-num2[i];
num1[i+1]-=1;
}
}
//输出过滤掉结果前面无效的0
while(num1[--i]==0)
{
if(i==0) break;
}
//输出符号位
if(flag==1) printf("-"); //flag=1,结果的符号位为负
//输出结果
for(j=i; j>=0; j--)
printf("%d",num1[j]);
printf("\n");
}
//当s1与s2异号,以正数-负数顺序传递实参给形参
void Minus(char s1[],char s2[])
{
len1=strlen(s1);
len2=strlen(s2);
for(i=len1-1,j=0; i>=0 ; i--) //s1为正数
{
num1[j]=s1[i]-48;
j++;
}
for(i=len2-1,j=0; i>0 ; i--) //s2为负数,s2[0]为符号位,不要
{
num2[j]=s2[i]-48;
j++;
}
memset(s3,0,sizeof(s3)); //为了便于比较同长度下的两个数的大小,将去掉负号的s2赋值给s3
for(i=1,j=0; i<len2; i++)
{
s3[j++]=s2[i];
}
//【3】 对应计算例子:(1)s1=11,s2=-9 ;(2)s1=106,s2=-104;(3)s1=11,s2=-11
//len1>(len2-1) 或 len1==(len2-1),s1>=s2 做num1-num2,设置flag=0,标志得正数
if(len1>(len2-1)||(len1==(len2-1)&&strcmp(s1,s3)==0)||len1==(len2-1)&&strcmp(s1,s3)==1)
{
Minus_show(0,len1,num1,num2);
}
//【4】对应计算例子:(1)s1=9,s2=-11 ;(2)s1=104,s2=-106
//(len2-1)>len1 或 len1==(len2-1),s1<s2 做num2-num1,设置flag=1,标志得负数
else if((len2-1)>len1||(len1==(len2-1)&&strcmp(s1,s3)==-1))
{
Minus_show(1,len2-1,num2,num1);
}
}
int main()
{
while(1)
{
//printf("please intput numbers:\n");
scanf("%s%s",s1,s2);
memset(num1,0,sizeof(num1));
memset(num2,0,sizeof(num2));
//【1】对应计算例子:(1)s1=11,s2=22;(2)s1=0,s2=0
if(s1[0]!='-'&&s2[0]!='-')
{
Plus(0); //s1与s2同正,设置flag=0
}
//【2】对应计算例子:(1)s1=-11,s2=-22
else if(s1[0]=='-'&&s2[0]=='-')
{
Plus(1); //s1与s2同负,设置flag=1
}
//【3】对应计算例子:s1=11,s2=-9
else if(s1[0]!='-'&&s2[0]=='-')
{
Minus(s1,s2); //s1为正,s2为负,传递s1,s2顺序,实现一个正数减一个负数
}
//【4】对应计算例子:s1=-9,s2=11
else
{
Minus(s2,s1); //s1为正,s2为负,传递s2,s1顺序,实现一个正数减一个负数
}
}
return 0;
}