高精度整数加法问题
求两个整数,a和b的和,(0=<a,b<=1e500)
高精度整数是个什么?
高精度整数就是超过整数类型(long long目前我学习到的最大整数类型)的正数,例如1e23+1e25等于多少?显然用long long也不够装,所以我们就要用字符串来处理。先来看看一个简单的例子999+111=?
999 +111 =1110
思路
这就需要回想起小学我们学的加减法了,借位(-)与进位(+)问题,分三个步骤来求解:
1.处理输入:用两个字符数组来保存a和b,ans数组表示最终答案
2.运算过程:遍历两个字符数组,算出结果的每一位数,ans[i]+=a[i]+b[i]-2*‘0’(这里要分开+,如果不分开+会出现意想不到的结果哦,分开加是为了避免加到的是-‘0’而不是0,会影响起结果);
如果ans[i]>9,则进位(ans[i+1]++,ans[i]%=10)
3.处理输出:输出要注意的就是答案不包含前导0的情况。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=505;
char a[MAXN],b[MAXN];
int ans[MAXN];
int main(){
scanf("%s%s",&a,&b);
int lena=strlen(a);
int lenb=strlen(b);
reverse(a,a+lena);
reverse(b,b+lenb);//反转两数组从个位算起
int n=max(lena,lenb);
for(int i=0;i<n;i++){
if(i<lena) ans[i]+=a[i]-'0';
if(i<lenb) ans[i]+=b[i]-'0';
if(ans[i]>9){//进位
ans[i]=ans[i]%10;
ans[i+1]+=1;
}
}
if(ans[n]!=0) printf("%d",ans[n]);
for(int i=n-1;i>=0;i--) printf("%d",ans[i]);
return 0;
}
高精度整数减法问题
求两个整数 a,b的差(第二个可能比第一个大,0=<a,b<=10086)。
思路
1.处理输入:输入两个字符串,我们后期算的时候就用大的数减小的数
这里尤其关键,举个例子234-345=?
234 -345 =-289
这是我算的,哈哈,我都不知道是怎么算的,最高位不够减我是怎么借来的,当时估摸着不对啊,口算也是-111啊,怎么就算到-289了,就发现问题所在了,我们只需要处理输入,每次将大的数赋给a,小的给b,然后用a-b来算,然后做个标记,如果交换则,最后输出一个负号即可,判断大小具体在代码里面。
2.运算过程:遍历两个字符数组,算出结果的每一位数,
ans[i]-=a[i]+b[i]-2*‘0’(这里要分开-,如果不分开-会出现意想不到的结果哦,分开加是为了避免减到的是-‘0’而不是0,会影响起结果);
如果ans[i]<0,则借位(ans[i+1]–,ans[i]+=10)
3.处理输出:还是前导0的情况。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10086+5;
char a[MAXN],b[MAXN];
int ans[MAXN];
int main(){
int flag=false;
scanf("%s%s",&a,&b);
int lena=strlen(a);
int lenb=strlen(b);
if(lenb>lena||(lena==lenb&&strcmp(a,b)<0)){
swap(a,b);
flag=true;//始终是大的减去小的,如果交换了,则最后加负号
}
lena=strlen(a);
lenb=strlen(b);
reverse(a,a+lena);
reverse(b,b+lenb);
for(int i=0;i<lena;i++){
if(i<lena) ans[i]+=a[i]-'0';
if(i<lenb) ans[i]-=b[i]-'0';
if(ans[i]<0){//借位
ans[i]+=10;
a[i+1]--;
}
}
int i=lena-1;
if(flag) printf("-");
while(ans[i]==0&&i>0) i--;//这里要留个位给最后的输出,万一等于0呢。
for(int j=i;j>=0;j--) printf("%d",ans[j]);
return 0;
}
高精度整数乘法问题
求两数的积。(0=<a,b<=1e2000)
思路
1.处理输入:用两个字符数组来保存a和b,ans数组表示最终答案;
2.运算过程:还是小学知识
999 * 99 =98901
我们先算999* 9,其原理和加法类似(ans[j]+=(a[j]-‘0’)(b[i]-‘0’)),如果ans[j]>9,则还是加到高一位去ans[j+1]=ans[j]/10;ans[j]%=10,然后算90 * 999=>9 999*10,我们可以这样处理,a数组遍历完一次了过后,则最低位加一位,然后继续进行乘法操作;
3.处理输出:前导0。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=2e3+5;
char a[MAXN],b[MAXN];
int ans[MAXN<<1];
int main(){
scanf("%s%s",&a,&b);
int lena=strlen(a);
int lenb=strlen(b);
reverse(a,a+lena);
reverse(b,b+lenb);
int k=0;
for(int i=0;i<lenb;i++){
for(int j=0;j<lena;j++){
int index=j+k;
ans[index]+=(b[i]-'0')*(a[j]-'0');
if(ans[index]>9){
ans[index+1]+=ans[index]/10;
ans[index]=ans[index]%10;
}
}
k++;
}
int i=lena+lenb-1;
while(ans[i]==0&&i>0) i--;//a*b最大lena+lenb位数,最小lena+lenb-1位数
for(int j=i;j>=0;j--) printf("%d",ans[j]);
return 0;
}
当然,具体问题具体分析,假如a和b包含负数加一些判断即可,下面的绝对值可不是真正的绝对值,只是去掉-,将原数组拷贝到新数组中:
1.a+b:
a>0,b<0=>a-|b|;
a<0,b>0=>b-|a|;
a<0,b<0=>-(|a|+|b|);
a>0,b>0=>a+b;
2.a-b:
a>0,b<0=>a+|b|;
a<0,b>0=>-(b+|a|);
a<0,b<0=>b-a;
a>0,b>0=>a-b;
3.a*b:
a>0,b<0=>-a * |b|;
a<0,b>0=>-b * |a|;
a<0,b<0=>|a| * |b|;
a>0,b>0=>a * b;