高精度那些事

高精度加减乘除板子,整理一下成为函数。

思路

都是字符串读入,倒序存储。数组\(a_0\)表示\(a\)的位数。

加法

每一位相加,判断是否需要进位。循环结束后判断最高位是否需要进位,最终调整一下位数。

减法

每一位相减,不够减的向前一位借位 (感觉我在学习小学一年级知识??)最后需要调整位数,去掉前导0.

乘法

这里和普通的竖式乘法不同。高精乘高精思路为,答案的第i+j-1位,等于两乘数分别的第 i 位和第 j 位相乘。最后需要处理进位和位数的问题。

除法

如上图,是地球人用纸和笔做的除法。但是很显然,计算机走试商的方法太麻烦,那就只能把除数移到被除数的最高位(空余的用0补上),再相减,直到剩下的数小于除数(同时记录商),然后进行下一位的计算。

代码

加法

#include<iostream>
#include"cmath"
#include<cstdio>
#include<algorithm>
using namespace std;
string in;
int a[999],b[999],ans[999];
int strlen(string x){
	int tot = 0;
	while(x[tot++] != '\0');
	return tot-1;
}
void _P(int x[],int y[]){
	ans[0] = max(x[0],y[0]);
	for(int i = 1;i <= ans[0]; i++){
		ans[i] += x[i] + y[i];
		ans[i+1] += ans[i]/10;
		ans[i] %= 10;
	}
	if(ans[ans[0] + 1]) ans[0] ++;
} 
int main(){
	cin >> in;
	a[0] = strlen(in);
	for(int i = 1;i <= a[0]; i++){
		a[i] = in[a[0] - i] - '0';
	}
	cin >> in;
	b[0] = strlen(in);
	for(int i = 1;i <= b[0]; i++){
		b[i] = in[b[0] - i] - '0';
	}
	_P(a,b);
	for(int i = ans[0];i >= 1; i--){
		cout << ans[i];
	}
	cout <<endl;
}

减法

注意正负号的检验。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
string in;
int a[10100],b[10100];
int c[10100];
int strlen(string x){
	int tot = 0;
	while(x[tot++] != '\0');
	tot--;
	return tot;
}
void jian(int x[],int y[]){
	c[0] = x[0];
	for(int i = 1;i <= x[0]; i++){ 
		c[i] += x[i]-y[i];
		if(c[i] < 0){
			c[i] += 10;
			c[i+1]--;
		}
	}
	while(c[0] > 1 && c[c[0]] == 0) c[0]--;
}
bool cmp(int x[],int y[]){
	if(x[0] > y[0]) return 1;
	if(x[0] < y[0]) return 0;
	for(int i = y[0];i >= 1; i--){
		if(x[i] > y[i]) return 1;
		if(x[i] < y[i]) return 0;
	}
	return 1;
}
int main(){
	cin >> in;
	a[0] = strlen(in);
	for(int i = 1;i <= a[0]; i++){
		a[i] = in[a[0] - i] - '0';
	}
	cin >> in;
	b[0] = strlen(in);
	for(int i = 1;i <= b[0]; i++){
		b[i] = in[b[0] - i] - '0';
	}
	if(!cmp(a,b)){
		for(int i = 0;i <= max(a[0],b[0]); i++){
			swap(a[i],b[i]);
		}
		cout << '-';
	}
	jian(a,b);
	for(int i = c[0];i >= 1; i--)
		cout << c[i] ;
	cout << endl; 
	return 0;
}

乘法

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
string in;
int a[999],b[999],ans[999];
int strlen(string x){
	int tot = 0;
	while(x[tot++] != '\0');
	return tot-1;
}
void _X(int x[],int y[]){
	ans[0] = x[0] + y[0]-1;
	for(int i = 1;i <= x[0]; i++){
		for(int j = 1;j <= y[0]; j++){
			ans[j+i-1] += x[i] * y[j];
			ans[i+j] += ans[j+i-1] / 10;
			ans[i+j-1] %= 10; 
		}
	}
	if(ans[ans[0]+1] != 0) ans[0]++;
	while(ans[0] > 1 && ans[ans[0]] == 0) ans[0]--;
} 
int main(){
	cin >> in;
	a[0] = strlen(in);
	for(int i = 1;i <= a[0]; i++){
		a[i] = in[a[0] - i] - '0';
	}
	cin >> in;
	b[0] = strlen(in);
	for(int i = 1;i <= b[0]; i++){
		b[i] = in[b[0] - i] - '0';
	}
	_X(a,b);
	for(int i = ans[0];i >= 1; i--){
		cout << ans[i];
	}
	cout <<endl;
	return 0;
} 

除法

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
string in;
int a[10100],b[10100];
int c[10100];
int d[10100],r[10100];
int strlen(string x){
	int tot = 0;
	while(x[tot++] != '\0');
	tot--;
	return tot;
}

void jian(int x[],int y[]){
	memset(c,0,sizeof c);
	c[0] = x[0];
	for(int i = 1;i <= x[0]; i++){ 
		c[i] += x[i]-y[i];
		if(c[i] < 0){
			c[i] += 10;
			c[i+1]--;
		}
	}
	while(c[0] > 1 && c[c[0]] == 0) c[0]--;
}

int cmp(int x[],int y[]){
	if(x[0] > y[0]) return 1;
	if(x[0] < y[0]) return 0;
	for(int i = y[0];i >= 1; i--){
		if(x[i] > y[i]) return 1;
		if(x[i] < y[i]) return 0;
	}
	return 2;
}
//商d,余数r
void chu(int x[],int y[]){
	memset(d,0,sizeof d);
	memset(r,0,sizeof r);
	int tmp[10100] = {};
	for(int i = 0;i <= x[0]; i++){
		r[i] = x[i];
	}
	d[0] = x[0];
	for(int i = x[0] - y[0] + 1;i >= 1; i--){
		memset(tmp,0,sizeof tmp);
		int cnt = 1;
		for(int j = i;j <= i + y[0] - 1; j++){
			tmp[j] = y[cnt++];//移位操作
		}
		for(int j = i-1; j >= 1; j--) tmp[j] = 0;
		tmp[0] = i-1 + y[0];
		while(cmp(r,tmp)){//比较除数和剩下的被除数
			d[i]++;
			jian(r,tmp);
			memset(r,0,sizeof r);
			for(int i = 0;i <= max(r[0],c[0]); i++) r[i] = c[i];
		}
	}
	while(d[0] > 1 && d[d[0]] == 0) d[0]--;
	while(r[0] > 1 && c[c[0]] == 0) r[0]--;
}
int main(){
	cin >> in;
	a[0] = strlen(in);
	for(int i = 1;i <= a[0]; i++){
		a[i] = in[a[0] - i] - '0';
	}
	cin >> in;
	b[0] = strlen(in);
	for(int i = 1;i <= b[0]; i++)
		b[i] = in[b[0]-i] - '0'; 
	
	chu(a,b);
	
	for(int i = d[0];i >= 1; i--) cout << d[i];
	cout << endl;
	for(int i = r[0];i >= 1; i--) cout << r[i];
	cout << endl;
	return 0;
}

例题

回文数

传送至洛谷 一本通

特殊的一点就是这里提到的是n进制,所以需要稍微进行一下优化(还好不是乘法除法)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[10086],b[10086];
int c[10086];
int n;string in;
int ans;
int strlen(string x){
	int tot = 0;
	while(x[tot++] != '\0');
	return tot-1;
}
void pluss(int x[],int y[],int k){//k进制
	memset(c,0,sizeof c);
	c[0] = max(x[0],y[0]);
	for(int i = 1;i <= max(x[0],y[0]); i++){
		c[i] += x[i] + y[i];
		if(c[i] >= k){
			c[i+1] += 1;
			c[i] %= k;//实际就是把10都改成了k
		}
	}
	if(c[c[0] + 1])
		c[0]++;
}
bool is_hw(int x[]){
	for(int i = 1;i <= x[0]; i++){
		if(x[i] != x[x[0] - i + 1]) return 0;
	}
	return 1;
}
int main(){
	cin >> n;
	cin >> in;
	a[0] = strlen(in);
	for(int i = 1;i <= a[0]; i++){
		if(in[a[0] - i] >= '0' && in[a[0] - i] <= '9')
			a[i] = in[a[0] - i] - '0';
		else
			a[i] = 10 + in[a[0]-i] -'A';
	}
	for(int i = 0;i <= a[0];i++) c[i] = a[i];
	while(!is_hw(c)){
		ans++;
		b[0] = c[0];
		a[0] = c[0];
		for(int i = 1;i <= c[0]; i++){
			b[i] = c[i];
			a[i] = c[c[0] + 1 -i];//倒序
		}
		pluss(a,b,n);
		if(ans >= 30){
			cout << "Impossible" << endl;
			return 0;
		}
	}
	cout << ans << endl;
	return 0;
}

阶乘之和

洛谷 一本通
这个真的是我也不知道为什么有点麻烦,之前是打表做的,今天重新写了一下。
整体如果出问题还是在高精的核心算法上。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[10000],b,anss[10000];
int n;
int ans[10000],now[10000];

void _x(int x,int y[]){
	memset(ans,0,sizeof ans);
	int x0 = 0,k = x;
	while(k){k /= 10; x0++;}
	ans[0] = x0 + y[0] -1;
	for(int i = 1;i <= max(y[0],x0); i++){
		ans[i] += x * y[i];
		k = i;
		while(ans[k] >= 10){
			ans[k+1] += ans[k] / 10;
			ans[k] %= 10;
			k++;
		}
		ans[0] = max(k,ans[0]);
	}
	while(ans[0] > 1 && ans[ans[0]] == 0) ans[0]--;
}

void _p(int x[],int y[]){
	memset(anss,0,sizeof anss);
	anss[0] = max(a[0],y[0]);
	for(int i = 1;i <= max(x[0],y[0]); i++){
		anss[i] += x[i] + y[i];
		if(anss[i] >= 10){
			anss[i+1] += anss[i] / 10;
			anss[i] %= 10; 
		}
	} 
	if(anss[anss[0]+1]){anss[0]++;}
	for(int i = 0;i <= anss[0]; i++)
		now[i] = anss[i];
} 
int main(){
	scanf("%d",&n);
	for(int i = 1;i <= n; i++){
		a[0] = a[1] = 1;
		for(int j = 1;j <= i; j++){
			_x(j,a);
			for(int i = 0;i <= a[0]; i++) a[i] = ans[i];
		}
		_p(ans,now);
	}
	for(int i = now[0];i >= 1; i--){
		cout << now[i];
	}
	cout << endl;
	return 0;
}

结尾

其实高精是个上哪里都不会考到的东西,但是这个确实有助于提高代码能力啥的。所以以后还是多写写吧。

posted @ 2020-07-02 16:37  柠月与梦  阅读(307)  评论(0编辑  收藏  举报