[总结/模板]高精度算法(四则运算)


当我们在进行四则运算的时候,如果需要处理的数据范围超过正常的数据类型,为了保证答案的正确性可以使用高精度算法。
高精度算法就是在模拟我们进行四则运算的过程。
不要试图指望_int128这种东西,用了也无卵用并且gcc也不支持。
在了解高精度算法之前,先让我们了解一些小知识:

  1. 如何将字符串转化为数组
  2. 高精度的比较

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;
}

pic.png

posted @ 2019-10-29 15:23  Wolfloral  阅读(440)  评论(0编辑  收藏  举报