B1-2:算法之高精度算法

首先回顾各种整数数据类型的数值范围:

image

显然上述任何数据类型都无法满足下列式子的计算和存储,例如:

123456789012345678901234567890+1=123456789012345678901234567891

当运算超出上述范围时候,就需要用高精度算法来存储和计算了。

一、高精度加法

高精度加法运算就是模拟数学中的竖式计算的一个过程:

image

用字符串数组来模拟上述过程:

image

代码实现:

//高精度加法标准原理写法 
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5;//1005; 常量 
int n;//变量 
char a[N],b[N];
int aa[N],bb[N],cc[N],ka=0,kb=0;

int main() {
	cin>>a>>b;
	int lena=strlen(a),lenb=strlen(b);
	int lenc=max(lena,lenb);
	for(int i=0;i<lena;i++){//把a转为int并倒序存入aa 
		aa[lena-i-1] =a[i]-'0';
	}

	for(int i=lenb-1;i>=0;i--){//把b转为int并倒序存入bb(方法二) 
		bb[lenb-i-1]=b[i]-'0';
		//bb[kb++]=b[i]-'0';//和上一行作用一样 
	}

	for(int i=0;i<lenc;i++){//aa,bb对应位置相加存入cc 
		cc[i]=aa[i]+bb[i];
	}
	for(int i=0;i<lenc;i++){//逐位检查是否有进位 
		cc[i+1]+=cc[i]/10;//进位存入高位 
		cc[i]%=10;//cc[i]=cc[i]%10;
	}
	if(cc[lenc])lenc++;//特判一下最高位是否有数字 
	for(int i=lenc-1;i>=0;i--)cout<<cc[i];//倒序输出cc即为a+b的答案 
	return 0;
}
//高精度加法二 
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5;//1005; 常量 
char a[N],b[N];
int cc[N];

int main() {
	cin>>a>>b;
	int ka=strlen(a)-1,kb=strlen(b)-1,kc=0;
	while(ka>=0 && kb>=0){//a[ka]+a[kb]存入对应的cc[kc] 
		cc[kc++]+=a[ka--]-'0'+b[kb--]-'0';
		cc[kc]+=cc[kc-1]/10;cc[kc-1]%=10;
	}
	while(ka>=0){//如果a比较长还没加完 
		cc[kc++]=a[ka--]-'0';//把a多余的部分搬到cc后面 
		cc[kc]+=cc[kc-1]/10;cc[kc-1]%=10;
	}
	while(kb>=0){//如果b比较长还没加完
		cc[kc++]=b[kb--]-'0';//把n多余的部分搬到cc后面
		cc[kc]+=cc[kc-1]/10;cc[kc-1]%=10;
	}
	if(!cc[kc])kc--;//判断高位是否有数 
	for(int i=kc;i>=0;i--)cout<<cc[i];
	return 0;
}

精简版代码图解

image

//高精度加法代码精简版
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5;//1005; 常量 
char a[N],b[N];
int c[N];
int main() {
	cin>>a>>b;
	int ka=strlen(a)-1,kb=strlen(b)-1,kc=0;
	//三个模拟指针,ka,kb分别指向a,b数组最高位,kc指向c数组最低位 
	while(ka>=0 || kb>=0){//只要还没加完 
		if(ka>=0)c[kc]+=a[ka--]-'0';//a[ka]没有加完则加入c[kc]中 
		if(kb>=0)c[kc]+=b[kb--]-'0';//同理,a[kb]合法则加入c[kc]中 
		c[kc+1]+=c[kc]/10;c[kc]%=10;//同时检查c[kc]进位给高位 
		kc++; //kc后移一位 
	}
	if(!c[kc])kc--;//判断高位是否有数 
	for(int i=kc;i>=0;i--)cout<<c[i];
	return 0;
}
高精度减法1
#include <bits/stdc++.h>
using namespace std;
string aa,bb;
bool flag=0;//默认符号为正数 
int a[1005],b[1005],c[1005];
void look(int x[],int k){
	cout<<endl;
	for(int i=0;i<=k;i++){
		cout<<x[i]<<" ";
	}
	cout<<endl;
}
int main() {
	cin>>aa>>bb;
	int la=aa.size(),lb=bb.size();
	//确保a>b;
	if(la<lb || (la==lb&&aa<bb)){
		flag=1;//flag为1说明结果为负数 
		swap(aa,bb);
		swap(la,lb);
	}

	for(int i=0;i<la;i++)//aa转为int倒序存储 
		a[i]=aa[la-i-1]-'0';
	
	for(int i=0;i<lb;i++)//bb转为int倒序存储
		b[i]=bb[lb-i-1]-'0';
	
	for(int i=0;i<la;i++){//逐位相减 
		c[i]=a[i]-b[i];
	}
	
	for(int i=0;i<la;i++){//检查借位 
		if(c[i]<0){
			c[i+1]--;
			c[i]+=10;
		}
	}
	
	int lc=la; 
	while(lc>0 && !c[lc])lc--;//删除前导0 
	
	if(flag)cout<<"-";
	for(int i=lc;i>=0;i--) cout<<c[i];
	return 0;
}
//高精度减法 2
#include <bits/stdc++.h>
using namespace std;
string aa,bb;
bool flag=0;//默认符号为正数 
int a[1005],b[1005],c[1005];
int main() {
	cin>>aa>>bb;
	int la=aa.size(),lb=bb.size();
	//确保a>b;
	if(la<lb || (la==lb&&aa<bb)){
		flag=1;//flag为1说明结果为负数 
		swap(aa,bb);swap(la,lb);		
	}
	for(int i=0;i<lb;i++)//bb转为int倒序存储
		b[i]=bb[lb-i-1]-'0';
		
	for(int i=0;i<la;i++){
		a[i]=aa[la-i-1]-'0';//aa转为int倒序存储 
		c[i]=a[i]-b[i];//逐位相减 
		if(c[i]<0){//检查借位
			c[i+1]--;
			c[i]+=10;
		}
	}
	
	int lc=la; 
	while(lc>0 && !c[lc])lc--;//删除前导0 
	
	if(flag)cout<<"-";
	for(int i=lc;i>=0;i--) cout<<c[i];
	
	return 0;
}
//高精度减法 3
#include <bits/stdc++.h>
using namespace std;
string a,b;
bool flag=0;//默认符号为正数 
int c[1005];
int main() {
	cin>>a>>b;
	int la=a.size(),lb=b.size();
	//确保a>b;
	if(la<lb || (la==lb&&a<b)){
		flag=1;//flag为1说明结果为负数 
		swap(a,b);swap(la,lb);		
	}
	
	int pa=la-1,pb=lb-1,pc=0;
	while(pa>=0){
		c[pc++]=a[pa--]-'0'-(b[pb--]-48);//逐位相减
		if(c[pc-1]<0){//检查借位
			c[pc]--;
			c[pc-1]+=10;
		}
	}
 
	while(pc>0 && !c[pc])pc--;//删除前导0 
	
	if(flag)cout<<"-";
	for(int i=pc;i>=0;i--) cout<<c[i];
	
	return 0;
}
//高精度乘法带符号
#include <bits/stdc++.h>
using namespace std;
string aa,bb;
int flaga=1,flagb=1;//默认符号为正数 
int a[1005],b[1005],c[1005];

int main() {
	cin>>aa>>bb;
	
	//特判符号部分 
	if(aa[0]=='-'){
		flaga=-1;//符号标记 
		aa.erase(0,1);//删除符号 
	};
	if(bb[0]=='-'){
		flagb=-1;//符号标记 
		bb.erase(0,1);//删除符号 
	};
	//特判符号部分 
	
	int la=aa.size(),lb=bb.size(),lc=la+lb;
	
	for(int i=0;i<la;i++)//aa转为int倒序存储 
		a[i]=aa[la-i-1]-'0';
		
	for(int i=0;i<lb;i++)//bb转为int倒序存储
		b[i]=bb[lb-i-1]-'0';

	for(int i=0;i<la;i++){
		for(int j=0;j<lb;j++){//逐位相乘 
			c[i+j]+=a[i]*b[j];
		}
	}
	
	for(int i=0;i<lc;i++){//处理进位 
		c[i+1]+=c[i]/10;
		c[i]%=10;;
	}

	while(lc>0 && !c[lc])lc--;//删除前导0 
	
	if(flaga*flagb<0)cout<<'-';//输出符号 
	for(int i=lc;i>=0;i--) cout<<c[i];
	return 0;
}
//高精度乘法带符号2
#include <bits/stdc++.h>
using namespace std;
string aa,bb;
int flaga=1,flagb=1,begina,beginb;//默认符号为正数 
int a[1005],b[1005],c[1005];
void look(int x[],int k){
	cout<<endl;
	for(int i=0;i<=k;i++){
		cout<<x[i]<<" ";
	}
	cout<<endl;
}
int main() {
	cin>>aa>>bb;
	int la=aa.size(),lb=bb.size(),lc=la+lb;
	if(aa[0]=='-')flaga=-1,begina=1;//符号为处理 
	if(bb[0]=='-')flagb=-1,beginb=1;//符号为处理
	for(int i=begina;i<la;i++)//aa转为int倒序存储 
		a[i-begina]=aa[la-i-1+begina]-'0';
		
	for(int i=beginb;i<lb;i++)//bb转为int倒序存储
		b[i-beginb]=bb[lb-i-1+beginb]-'0';

	for(int i=0;i<la;i++){
		for(int j=0;j<lb;j++){//逐位相乘 
			c[i+j]+=a[i]*b[j];
		}
	}
	

	for(int i=0;i<lc;i++){//处理进位 
		c[i+1]+=c[i]/10;
		c[i]%=10;;
	}

	while(lc>0 && !c[lc])lc--;//删除前导0 
	
	if(flaga*flagb<0)cout<<'-';
	for(int i=lc;i>=0;i--) cout<<c[i];
	return 0;
}
//高精度除以单精度
#include <bits/stdc++.h>
using namespace std;
string aa;
bool flag=0;//默认符号为正数 
long long a[1005],b,c[1005],r,pc=0;
int main() {
	cin>>aa>>b;
	int la=aa.size(),lc=la;
	
	for(int i=0;i<la;i++)//aa转为int倒序存储 
		a[i]=aa[i]-'0';
	
	for(int i=0;i<la;i++){
		c[i]=(r*10+a[i])/b;
		r=(r*10+a[i])%b;
	}
	
	while(pc<la && !c[pc])pc++;//删除前导0 
	
	for(int i=pc;i<lc;i++) cout<<c[i];
	//cout<<endl<<r;//输出余数
	return 0;
}