例67 大整數加法
問題描述
求兩個不超過200位的非負整數的和。
輸入
有兩行,每行是一個不超過200位的非負整數,可能有多余的前導0。
輸出
一行,即相加后的結果。結果里不能有多余的前導0,即如果結果是342,那么就不能輸出為0342。
輸入樣例
22222222222222222222
33333333333333333333
輸出樣例
55555555555555555555
(1)編程思路。
可以用一個字符串來保存200位整數。
編寫函數void add(char *a,char *b,char *c)實現大整數c=a+b。
在函數中可以用數組unsigned x[201]來保存一個200 位的整數a,讓x[0]存放個位數,x[1]存放十位數,x[2]存放百位數……。
實現兩個大整數相加的方法很簡單,就是模擬小學生列豎式做加法,從個位開始逐位相加,超過或達到10 則進位。
(2)源程序。
#include <stdio.h>
#include <string.h>
void add(char *a,char *b,char *c)
{
int len1=strlen(a),len2=strlen(b);
int x[201],y[201],z[205];
int len=len1>len2?len1:len2;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(z,0,sizeof(z));
int i;
for (i=len1-1;i>=0;i--)
x[len1-1-i]=a[i]-'0';
for (i=len2-1;i>=0;i--)
y[len2-1-i]=b[i]-'0';
int cf=0;
for (i=0;i<len;i++)
{
z[i]=(x[i]+y[i]+cf)%10;
cf=(x[i]+y[i]+cf)/10;
}
z[len++]=cf;
while (len>0 && z[len-1]==0) // 去前置0
len--;
if (len==0) // a+b=0時特判
{
c[0]='0';
c[1]='\0';
return ;
}
for (i=0;i<len;i++)
c[i]=z[len-1-i]+'0';
c[len]='\0';
}
int main()
{
char s1[201],s2[201],ans[205];
scanf("%s%s",s1,s2);
add(s1,s2,ans);
printf("%s\n",ans);
return 0;
}
習題67
67-1 二進制加法
問題描述
給出兩個二進制數a和b的01串,按二進制加法計算a+b並輸出。
輸入
第1行為一個整數T,表示測試用例的組數,之后T行,每行包括兩個01串,每個串長不超過80位。
輸出
對於每組測試用例,輸出兩個01串相加的結果(最簡形式)。
輸入樣例
3
1001101 10010
1001001 11001
1000111 1010110
輸出樣例
1 1011111
2 1100010
3 10011101
(1)編程思路。
二進制數高精度加法,注意前置0的處理。
(2)源程序。
#include <stdio.h>
#include <string.h>
void binAdd(char *a,char *b,char *c)
{
int len1=strlen(a),len2=strlen(b);
int x[91],y[91],z[91];
int len=len1>len2?len1:len2;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(z,0,sizeof(z));
int i;
for (i=len1-1;i>=0;i--)
x[len1-1-i]=a[i]-'0';
for (i=len2-1;i>=0;i--)
y[len2-1-i]=b[i]-'0';
int cf=0;
for (i=0;i<len;i++)
{
z[i]=(x[i]+y[i]+cf)%2;
cf=(x[i]+y[i]+cf)/2;
}
z[len++]=cf;
while (len>0 && z[len-1]==0) // 去前置0
len--;
if (len==0) // a+b=0時特判
{
c[0]='0';
c[1]='\0';
return ;
}
for (i=0;i<len;i++)
c[i]=z[len-1-i]+'0';
c[len]='\0';
}
int main()
{
char s1[91],s2[91],ans[91];
int n,i;
scanf("%d",&n);
for (i=1;i<=n;i++)
{
scanf("%s%s",s1,s2);
binAdd(s1,s2,ans);
printf("%d %s\n",i,ans);
}
return 0;
}
67-2 大整數減法
問題描述
求兩個大的正整數相減的差。
輸入
共2行,第1行是被減數a,第2行是減數b(a > b)。每個大整數不超過200位,不會有多余的前導零。
輸出
一行,即所求的差。
輸入樣例
9999999999999999999999999999999999999
9999999999999
輸出樣例
9999999999999999999999990000000000000
(1)編程思路。
可以用一個字符串來保存200位整數。
編寫函數voidsub(char *a,char *b,char *c)實現大整數c=a-b。
在函數中可以用數組unsigned x[201]來保存一個200 位的整數a,讓x[0]存放個位數,x[1]存放十位數,x[2]存放百位數……。
實現兩個大整數相減的方法很簡單,就是模擬小學生列豎式做減法,從個位開始逐位相減,小於0則向前借位補10。
(2)源程序。
#include <stdio.h>
#include <string.h>
void sub(char *a,char *b,char *c)
{
int len1=strlen(a),len2=strlen(b);
int x[210],y[210],z[210];
int len=len1;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(z,0,sizeof(z));
int i,j;
for (i=len1-1,j=0;i>=0;i--,j++)
x[j]=a[i]-'0';
for (i=len2-1,j=0;i>=0;i--,j++)
y[j]=b[i]-'0';
int cf=0;
for (i=0;i<len;i++)
{
z[i]=x[i]-y[i]+cf;
if (z[i]<0)
{
z[i]+=10;
cf=-1;
}
else
cf=0;
}
while (len>0 && z[len-1]==0) // 去前置0
len--;
if (len==0) // a-b=0時特判
{
c[0]='0';
c[1]='\0';
return ;
}
for (i=0;i<len;i++)
c[i]=z[len-1-i]+'0';
c[len]='\0';
}
int main()
{
char a[210],b[210],c[210];
scanf("%s", a);
scanf("%s", b);
sub(a,b,c);
printf("%s\n",c);
return 0;
}
67-3 求和
問題描述
已知兩個整數a和b,求a+b的值
輸入
第一行包含一個整數T,即測試用例的數量。
以下T行,每行分別包含2個整數A、B(-10^50000<A、B<32768)。
輸出
輸出應該包含T行,每個行都有一個整數,代表相應的和。
輸入樣例
2
1 2
-1 +2
輸出樣例
3
1
(1)編程思路。
由於a和b可能小於0,因此a+b分為4種情況:
1)a>=0,b>=0,則進行a+b;
2)a<0,b<0,則進行(-a)+(-b);
3)a>=0,b<0,則進行a-(-b);此時還需對a和(-b)進行大小比較,按比較情況執行a-(-b)或(-b)-a;
4)3)a<0,b>=0,則進行b-(-a);此時還需對-a和b進行大小比較,按比較情況執行b-(-a)或(-a)-b。
(2)源程序。
#include <stdio.h>
#include <string.h>
void add(char *a,char *b,char *c)
{
int len1=strlen(a),len2=strlen(b);
int x[51000],y[51000],z[51000];
int len=len1>len2?len1:len2;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(z,0,sizeof(z));
int i;
for (i=len1-1;i>=0;i--)
x[len1-1-i]=a[i]-'0';
for (i=len2-1;i>=0;i--)
y[len2-1-i]=b[i]-'0';
int cf=0;
for (i=0;i<len;i++)
{
z[i]=(x[i]+y[i]+cf)%10;
cf=(x[i]+y[i]+cf)/10;
}
z[len++]=cf;
while (len>0 && z[len-1]==0) // 去前置0
len--;
if (len==0) // a+b=0時特判
{
c[0]='0';
c[1]='\0';
return ;
}
for (i=0;i<len;i++)
c[i]=z[len-1-i]+'0';
c[len]='\0';
}
void sub(char *a,char *b,char *c)
{
int len1=strlen(a),len2=strlen(b);
int x[51000],y[51000],z[51000];
int len=len1;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(z,0,sizeof(z));
int i;
for (i=len1-1;i>=0;i--)
x[len1-1-i]=a[i]-'0';
for (i=len2-1;i>=0;i--)
y[len2-1-i]=b[i]-'0';
int cf=0;
for (i=0;i<len;i++)
{
z[i]=x[i]-y[i]+cf;
if (z[i]<0)
{
z[i]+=10;
cf=-1;
}
else
cf=0;
}
while (len>0 && z[len-1]==0) // 去前置0
len--;
if (len==0) // a-b=0時特判
{
c[0]='0';
c[1]='\0';
return ;
}
for (i=0;i<len;i++)
c[i]=z[len-1-i]+'0';
c[len]='\0';
}
int bigger(char *a,char *b)
{
if (strlen(a)>strlen(b)) return 1;
if (strlen(a)<strlen(b)) return 0;
if (strcmp(a,b)>=0) return 1;
else return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
char a[51000],b[51000],ans[51000];
scanf("%s%s",a,b);
if (a[0]=='+') strcpy(a,&a[1]);
if (b[0]=='+') strcpy(b,&b[1]);
int sign;
if (a[0]!='-' && b[0]!='-') // a+b
{
add(a,b,ans);
sign=0;
}
else if (a[0]=='-' && b[0]=='-') // -a-b=-(a+b)
{
add(&a[1],&b[1],ans);
sign=1;
}
else if (a[0]!='-' && b[0]=='-') // a-b
{
if (bigger(a,&b[1]))
{
sub(a,&b[1],ans);
sign=0;
}
else // b>a,a-b=-(b-a)
{
sub(&b[1],a,ans);
sign=1;
}
}
else // b-a
{
if (bigger(b,&a[1])) // b>a
{
sub(b,&a[1],ans);
sign=0;
}
else // b<a,b-a=-(a-b)
{
sub(&a[1],b,ans);
sign=1;
}
}
if (sign==1 && ans[0]!='0') printf("-");
printf("%s\n",ans);
}
return 0;
}