【基础算法】高精度运算

高精度运算

如果出题老师想要难为你,他可能会给你构造一些超出int,甚至long long 范围的数据
在这里插入图片描述
在你瞪着RE发呆的时候,考虑考虑数据范围——是不是该用高精度了?

数据太大,只能当字符串读(只针对数字,因为如果是字符串就直接读了)

读入优化

  • 普通的读入优化:
//读整数 
int Read(){
	int i=0,f=1;//i读数字,f读符号 
	char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());//一路避开不是数字或负号的字符,最后一次读到首位或负号 
	if(ch=='-'){
		f=-1;
		ch=getchar();
	}
	for(;isdigit(ch);ch=getchar()){
		i=(i<<3)+(i<<1)+ch-'0';
	}
	return i*f;
}
//如果只有正整数,情况就会简单得多 
int Read(){
	int i=0;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar());
	for(;isdigit(ch);ch=getchar()){
		i=(i<<3)+(i<<1)+ch-'0';
	}
	return i;
}
  • 稍微修改一下——把数据都读到字符串/数组里,再大的位数都接受得了
//高精度读法   为了计算方便,倒着存数字
void Read(){
	int i=0,num[1000];
	char ch;//num存数据(从下标0或1开始都行) 
	for(ch=getchar();!isdigit(ch);ch=getchar());
	//次for循环不要也行,用scanf("%d ",&x)消掉空格,scanf("%d\n",&x)消掉换行符
	//小心getline,gets等语句会读空格,换行符 
	
	
	//不知道数位用这个: 
	int a[1000];
	for(;isdigit(ch);ch=getchar()){ 
		i++;
		a[i]=ch-'0';
	}
	while(i--){
		num[j]=a[i];
		j++;
	}
	
	//知道数位:
	for(int i=n-1;i>=0;i--){
		num[i]=ch-'0';
		ch=getchar();
	}
}
//如果你喜欢用数组,try this 
void Read(){
	int i=0,num[1000];
	char ch[1000];
	/*选一个*/cin>>ch;scanf("%s",ch);gets(ch)/*小心它的换行符*/
	for(int i=0;i<strlen(ch);i++)
		num[strlen(ch)-i-1]=ch[i]-'0';
}

高精度四则运算

模拟普通的四则运算,数位是倒着写的

  • 加法
#include<bits/stdc++.h>
using namespace std;

char ch[300];
int x,a[300],b[300],c[300],n,m;

int main()
{
	cin>>ch;
	n=strlen(ch);
	for(int i=0;i<n;i++)
		a[n-i]=ch[i]-'0';
		
	cin>>ch;
	m=strlen(ch);
	for(int i=0;i<m;i++)
		b[m-i]=ch[i]-'0';
	
	if(n<m)n=m;
		
	x=0;
	for(int i=1;i<=n;i++)
	{
		c[i]=(a[i]+b[i]+x)%10;
		x=(a[i]+b[i]+x)/10;
	}
	
	if(x>0)
	{
		n++;
		c[n]=x;
	}
	
	for(int i=n;i>=1;i--)
		cout<<c[i];
	return 0;
} 

Tips:

  1. /10去个位,%10取个位
  2. 初识进位
  • 减法
#include<bits/stdc++.h>
using namespace std;

string st1,st2;
int n,m,a[300],b[300],s[300],x;

int main()
{
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(s,0,sizeof(s));
	
	cin>>st1;
	n=st1.size();
	for(int i=0;i<n;i++)
		a[n-i]=st1[i]-'0';
	
	cin>>st2;
	m=st2.size();
	for(int i=0;i<m;i++)
		b[m-i]=st2[i]-'0';
	
	if(m>n||(m==n&&st1<st2))
	{
		cout<<"-";
		for(int i=1;i<=m;i++)
			swap(a[i],b[i]);
		swap(m,n);
	}
	
	for(int i=1;i<=n;i++)
	{
		x=a[i]+10-b[i];
		s[i]=x%10;
		a[i+1]=a[i+1]+x/10-1;//下一位被减数,注意借位 
	}
	
	while(n>1&&s[n]==0)n--;
	
	for(int i=n;i>=1;i--)cout<<s[i];//i--!!!!!!!!
	
	return 0;
} 

Tips:

  1. 管他三七二十一,先借一位再说
  2. 出来借,总是要还的
  3. 小心负数
  • 乘法
#include<bits/stdc++.h>
using namespace std;

char ch[300];
int a[300],b[300],s[300],n,m,x,w;

int main()
{
	cin>>ch;
	n=strlen(ch);
	for(int i=0;i<n;i++)a[n-i]=ch[i]-'0';
	
	cin>>ch;
	m=strlen(ch);
	for(int i=0;i<m;i++)b[m-i]=ch[i]-'0';
	
	for(int i=1;i<=n;i++)
	{
		x=0;
		for(int j=1;j<=m;j++)
		{
			x=a[i]*b[j]+x+s[i+j-1];
			s[i+j-1]=x%10;
			x=x/10;
		}
		s[i+m]=s[i+m]+x;//reminder:乘法最高位=以前重叠位数+进位 
	}
	
	w=n+m;//reminder:n位数*m位数→n+m位数 
	
	while(s[w]==0&&w>1)w--;
	
	for(int i=w;i>0;i--)cout<<s[i];
	
	return 0;
} 

Tips:

  1. 乘法的进位可能会超过10,不用担心,只要塞给下一位,下一位就会处理好
  2. n位数*m位数得到(n+m)位数
  3. 结果不一定就一定是(n+m)位数,再输出之前还要去首位之前无意义的零
  • 除法(高精度除以单精度)
#include<bits/stdc++.h>
using namespace std;

int cs,bcs[300],shang[300],n,x,j;
char ch[300];

int main()
{
	cin>>ch;
	cin>>cs;
	
	n=strlen(ch);
	for(int i=0;i<n;i++)bcs[i]=ch[i]-'0';
	
	for(int i=0;i<n;i++)
	{
		shang[i]=(bcs[i]+10*x)/cs;
		x=(bcs[i]+x*10)%cs;
	}
	
	while(shang[j]==0&&n>j)j++;
	
	for(int i=j;i<n;i++)cout<<shang[i];
	cout<<endl;
	cout<<x;
	return 0;
}

Tips:

  1. 除法反而是最简单的(高精度除以单精度)
  2. 数组顺着存都没问题(而且更好)
  3. 也要记得去首位之前无意义的零
发布了26 篇原创文章 · 获赞 3 · 访问量 917

猜你喜欢

转载自blog.csdn.net/Antimonysbguy/article/details/97925439