高精度算法(大数的加、减、乘、除)

文章详细介绍了如何在C++中处理大数的加法、减法、乘法和除法,包括使用逆序存储、高精度算法以及去除前导零的过程。重点讨论了长整型(int和longlong)在不同场景下的使用和处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在C/C++中,int占一个机器字长,32位机中则占4个字节,即[-2^31,2^31-1](10的9次方数量级)。不管是32位还是64位机,long long占8个字节,即[-2^63,2^63-1](10的18次方数量级)。

如果超过该数量级,应该使用高精度算法。

1 加

1、将两个加数逆序存储在两个int数组中。(逆序的原因是方便操作和数据对齐,加法计算都是从低位开始操作,逆序的话就把最低位存在a[0]、b[0]这个位置)

2、两个加数的和,它的最大长度是较长的那个加数的长度+1(lc=max(la,lb)+1)。如果和不是最大长度的话,就会有前导0,需要去除。

3、核心算法:

        c[i]+=a[i]+b[i];
        c[i+1]=c[i]/10;
        c[i]=c[i]%10;

#include<iostream>
#include<string>
using namespace std;
const int N=100;//大数的长度
int a[N],b[N],c[N];

void add(string s1,string s2){
	for(int i=0;i<s1.length();i++){
		a[s1.length()-i]=s1[i]-'0';//逆序存储 
	}
	for(int i=0;i<s2.length();i++){
		b[s2.length()-i]=s2[i]-'0';
	}
	int lc=max(s1.length(),s2.length())+1;
	for(int i=1;i<=lc;i++){
		c[i]+=a[i]+b[i];//有进位,所以是+= 
		c[i+1]=c[i]/10;
		c[i]=c[i]%10;
	} 
	while(lc>1&&c[lc]==0) lc--;//去前导0
	for(int i=lc;i>=1;i--){//逆序输出 
		cout<<c[i];
	} 
	cout<<endl;
}
int main(){
	string s1,s2;
	cin>>s1>>s2;
	add(s1,s2);
	return 0;
} 

2 减

1、比较大小,用大的减小的,如果s1大于s2,输出。如果小于,就添一个负号。 

2、将被减数和减数逆序存储在int数组中。(逆序:和前面的加法一样,减法也是从低位开始计算的)

3、计算得到的差,最长长度也只有被减数那么长(lc=la)。如果没有到达最长长度,需要去除前导0

4、核心算法

        if(a[i]<b[i]){

                a[i+1]--;

                a[i]+=10;

        }

        c[i]=a[i]-b[i];

#include<iostream>
#include<string>
using namespace std;
const int N=100;//大数的长度
int a[N],b[N],c[N];
bool cmp(string s1,string s2){
	if(s1.length()!=s2.length()) return s1.length()>s2.length();
	for(int i=0;i<s1.length();i++){
		if(s1[i]!=s2[i]) return s1[i]>s2[i];
	}
	return true;
}
void subtract(string s1,string s2){
	for(int i=0;i<s1.length();i++){
		a[s1.length()-i]=s1[i]-'0';//逆序存储 
	}
	for(int i=0;i<s2.length();i++){
		b[s2.length()-i]=s2[i]-'0';
	}
	int lc=s1.length();
	for(int i=1;i<=lc;i++){
		if(a[i]<b[i]){
			a[i+1]--;
			a[i]+=10;
		}
		c[i]=a[i]-b[i];
	} 
	while(lc>1&&c[lc]==0) lc--;//去前导0
	for(int i=lc;i>=1;i--){//逆序输出 
		cout<<c[i];
	} 
	cout<<endl;
}
int main(){
	string s1,s2;
	cin>>s1>>s2;
	if(cmp(s1,s2)){
		subtract(s1,s2);
	}else{
		cout<<"-";
		subtract(s2,s1);
	}
	return 0;
} 

3 乘

1、逆序存储两个乘数

2、乘积的最长长度为两个乘数的长度之和(lc=la+lb)。

3、a[i]*b[j]位置对应c[i+j-1]位置。核心代码:

                c[i+j-1]+=a[i]*b[j];

                c[i+j]+=c[i+j-1]/10;

                c[i+j-1]%=10;

#include<iostream>
#include<string>
using namespace std;
const int N=100;
int a[N],b[N],c[N];

void multiply(string s1,string s2){
	for(int i=0;i<s1.length();i++){
		a[s1.length()-i] =s1[i]-'0';//逆序存储 
	}
	for(int i=0;i<s2.length();i++){
		b[s2.length()-i] =s2[i]-'0';
	}
	int lc=s1.length()+s2.length();//乘积的最长长度
	for(int i=1;i<=s1.length();i++){
		for(int j=1;j<=s2.length();j++){
			c[i+j-1]+=a[i]*b[j];
			c[i+j]+=c[i+j-1]/10;
			c[i+j-1]%=10;
		}
	} 
	while(lc>1&&c[lc]==0) lc--;
	for(int i=lc;i>=1;i--){
		cout<<c[i];
	}
	cout<<endl;
}
int main(){
	string s1,s2;
	cin>>s1>>s2;
	multiply(s1,s2);
	return 0;
}

4 除

4.1 高精度÷低精度

1、将高精度的被除数存入int数组,不需要逆序存储,因为除法是从高位开始的。

2、商的最长长度为被除数的长度(lc=la,实际上是lc=la-lb+1,但是b不是高精度的不方便求,这里长度放大一些也没关系),如果没有达到,需要去除前导0

3、核心算法

        c[i]=(r*10+a[i])/b;

        r=(r*10+a[i])%b;

#include<iostream>
#include<string>
using namespace std;
const int N=100;
int a[N],c[N];

void divide(string s1,int b,int &r){
	for(int i=0;i<s1.length();i++){
		a[i+1]=s1[i]-'0';//不需要逆序存储 
	}
	int lc=s1.length();
	for(int i=1;i<=lc;i++){
		c[i]=(r*10+a[i])/b;
		r=(r*10+a[i])%b; 
	}
	int x=1;
	while(c[x]==0&&x<lc) x++;//去前导0 
	for(int i=x;i<=lc;i++){
		cout<<c[i];
	}
	cout<<endl; 
}
int main(){
	string s1;
	int b;
	cin>>s1>>b;
	int r=0;
	divide(s1,b,r);
	cout<<"余数为:"<<r<<endl; 
	return 0;
}

4.2 高精度÷高精度

减法模拟除法,因此本质上是减法,所以存储时需要倒序存储。

以下默认被除数大于等于除数,如果小于的话,答案为0,余数为被除数。

1、将被除数和除数倒序存储在int数组中。

2、商的最长长度为lc=la-lb+1

3、减法模拟。核心算法:

        for(int i=lc;i>=1;i--){

                memset(temp,0,sizeof(temp));//temp也是高精度的,将其清空

                高精度除数左移lc-1位,存在temp中

                while(a>=temp){//高精度比较

                        a[i]++;

                        a=a-temp;//高精度减法   最后的余数也就是a

                }

        }

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int N=100;
int a[N],b[N],c[N],temp[N];//temp数组为除数左移之后的值 
bool cmp(string s1,string s2){
	if(s1.length()!=s2.length()) return s1.length()>s2.length();
	for(int i=0;i<s1.length();i++){
		if(s1[i]!=s2[i]) return s1[i]>s2[i];
	}
	return true;
}
//除数左移 
void move(int b[],int temp[],int x){
	for(int i=1;i<=x;i++){
		temp[i]=0;
	}
	for(int i=1;i<=b[0];i++){
		temp[i+x]=b[i];
	}
	temp[0]=b[0]+x; 
} 
bool compare(int a[],int temp[]){
	if(a[0]!=temp[0]) return a[0]>temp[0];
	for(int i=a[0];i>=1;i--){
		if(a[i]!=temp[i]) return a[i]>temp[i];
	}
	return true;
}
//减法 a=a-temp 
void jian(int a[],int temp[]){
	for(int i=1;i<=a[0];i++){
		if(a[i]<temp[i]){
			a[i+1]--;
			a[i]+=10;
		}
		a[i]=a[i]-temp[i];
	}
	while(a[0]>1&&a[a[0]]==0) a[0]--;
}
void divide(string s1,string s2){
	a[0]=s1.length();//用a[0]存储它的长度 
	b[0]=s2.length();
	for(int i=0;i<s1.length();i++){
		a[s1.length()-i]=s1[i]-'0';//逆序存储 
	}
	for(int i=0;i<s2.length();i++){
		b[s2.length()-i]=s2[i]-'0';
	}
	int lc=s1.length()-s2.length()+1;
	for(int i=lc;i>=1;i--){
		memset(temp,0,sizeof(temp));
		move(b,temp,i-1);//将除数左移i-1位 存在temp数组中 
		while(compare(a,temp)){//a>=temp 
			c[i]++;
			jian(a,temp);//a=a-temp
		}
	}
	while(lc>1&&c[lc]==0) lc--;
	for(int i=lc;i>=1;i--){
		cout<<c[i];
	}
	cout<<endl;
	cout<<"余数为:";
	//余数即为改变后的a
	for(int i=a[0];i>=1;i--){
		cout<<a[i];
	} 
	cout<<endl;
}
int main(){
	string s1,s2;
	cin>>s1>>s2;
	divide(s1,s2);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个有思想的逗号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值