当我们在进行四则运算的时候,如果需要处理的数据范围超过正常的数据类型,为了保证答案的正确性可以使用高精度算法。
高精度算法就是在模拟我们进行四则运算的过程。
在了解高精度算法之前,先让我们了解一些小知识:
- 如何将字符串转化为数组
- 高精度的比较
1. 字符串转化为数组:
我们依次扫描的字符串是由高位指向低位的,而我们计算的时候却是由低位向高位进行的。这时候我们可以用string.size-i
巧妙地转化。
这里给出string类型和char类型两种方法:
String:
string A,B;
int a[100]={0},b[100]={0};
int na=A.length();
for(i=1;i<=na;i++) a[i]=A[na-i]-'0';
int nb=B.length();
for(i=1;i<=nb;i++) b[i]=B[nb-i]-'0';
Char:
char A[100],B[100];
scanf("%s%s",A,B);
int na=strlen(A),nb=strlen(B);
for(int i=0;i<na;i++) a[na-i]=A[i]-'0';
for(int i=0;i<nb;i++) b[nb-i]=B[i]-'0';
2. 高精度的比较:
首先按位数比较,位数多的数一定越大(正整数范围);其次按照每位整数大小比较,由高位至低位依次比较大小。若以上两条件都没有返回判断,那么这两个大整数相等。
inline bool compare_size(){
if(na>nb) return 1;
if(na<nb) return 0;
for(int i=na;i>=1;i--){
if(a[i]>b[i]) return 1;
if(a[i]<b[i]) return 0;
}
return -1;
}
接下来是正文
一、高精度加法
P1601 A+B Problem(高精)
高精度加法是相对简单的一类高精度。值得注意的地方是建立一个变量ext(extra)
表示当前位的进位,并且要删掉前导0。
Code:
#include<bits/stdc++.h>
#define N 1000010
using namespace std;
char A[N],B[N];
int a[N],b[N],c[N],na,nb,nc,ext;//数组c存放最终结果
inline void change_to_number(){
for(int i=0;i<na;i++) a[na-i]=A[i]-'0';
for(int i=0;i<nb;i++) b[nb-i]=B[i]-'0';
}//转化成单个数字
int main()
{
scanf("%s%s",A,B);
na=strlen(A),nb=strlen(B);
change_to_number();
nc=1;
while(nc<=na||nc<=nb){
c[nc]=a[nc]+b[nc]+ext;
ext=c[nc]/10;//求进位
c[nc]%=10;nc++;
}
c[nc]=ext;
if(!c[nc]) nc--;
for(int i=nc;i>=1;i--) printf("%d",c[i]); //倒序输出
return 0;
}
二、高精度减法
P2142 高精度减法
高精度减法的借位处理与加法类似,被减数不够减便向高位借一位,并在该位加10再处理。
处理后产生的前导0,需要我们手动处理。
最后需要解决答案是负数的问题,这里给出一种很简单的方法:预先比较被减数与减数的大小,如果被减数小于减数,那么交换这两个数并在答案前面加上'-'
。
以上就完成了高精度减法的处理,细节见代码:
Code:
#include<bits/stdc++.h>
#define N 20010
using namespace std;
char A[N],B[N];
int a[N],b[N],na,nb;
inline bool compare_size(){//大整数比较
if(na>nb) return 1;
if(na<nb) return 0;
for(int i=na;i>=1;i--){
if(a[i]>b[i]) return 1;
if(a[i]<b[i]) return 0;
}
return 1;
}
inline void change_to_number(){
for(int i=0;i<na;i++) a[na-i]=A[i]-'0';
for(int i=0;i<nb;i++) b[nb-i]=B[i]-'0';
}
int main()
{
scanf("%s%s",A,B);//A是被减数,B是减数
na=strlen(A),nb=strlen(B);
change_to_number();
if(compare_size()){//被减数大于减数
for(int i=1;i<=na;i++){
a[i]-=b[i];
if(a[i]<0) a[i+1]--,a[i]+=10;//不够减,进位
}
while(!a[na]&&na>1) na--;//去掉0
for(int i=na;i>=1;i--) printf("%d",a[i]);
}
else{//小于减数
printf("-");
for(int i=1;i<=nb;i++){
b[i]-=a[i];
if(b[i]<0) b[i+1]--,b[i]+=10;
}
while(!b[nb]&&nb>1) nb--;
for(int i=nb;i>=1;i--) printf("%d",b[i]);
}
return 0;
}
三、高精度乘法
P1303 A*B Problem
在小学大家一定都练习过竖式乘法,所以高精乘与我们小学学过的方法是一样的,被乘数的第\(i\)位与乘数的第\(j\)位落在第\(i+j-1\)位(不懂得话可以手动模拟一下),如果结果大于10,那么进位并将自身\(mod10\)。具体详见代码:
Code:
#include<bits/stdc++.h>
#define N 250000
using namespace std;
char A[N],B[N];
int a[N],b[N],c[N],na,nb;
inline void change_to_number(){
for(int i=0;i<na;i++) a[na-i]=A[i]-'0';
for(int i=0;i<nb;i++) b[nb-i]=B[i]-'0';
}
int main()
{
scanf("%s%s",A,B);
na=strlen(A),nb=strlen(B);
change_to_number();
for(int i=1;i<=na;i++)
for(int j=1;j<=nb;j++){
c[i+j-1]+=a[i]*b[j];
c[i+j]+=c[i+j-1]/10;//进位
c[i+j-1]%=10;
}
int nc=na+nb;//最终位数
while(nc>1&&!c[nc]) nc--;//去除前导0
for(int i=nc;i>=1;i--) printf("%d",c[i]);
return 0;
}
四、高精度除法
给出高精除低精的算法,每次按位除以除数,并不断更新余数。
Code:
#include<bits/stdc++.h>
#define N 10010
using namespace std;
char A[N],C[N];
int a[N],c[N],b,na,nc,rest;
int main()
{
scanf("%s%d",A,&b);
na=strlen(A);
for(int i=1;i<=na;i++) a[i]=A[i-1]-'0';
for(int i=1;i<=na;i++){
c[i]=(rest*10+a[i])/b;
rest=(rest*10+a[i])%b;
}
while(!c[nc]&&nc<na) nc++;
for(int i=nc;i<=na;i++) printf("%d",c[i]);
return 0;
}