C++高精度加减乘除模板

1.1 高精度加法

给定两个正整数(不含前导 00),计算它们的和。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的和。

数据范围

1≤整数长度≤100000

输入样例:
12
23
输出样例:
35
  • 思路:因为int最多只能2e9,longlong 最多只能9.2e18,对于题目要求的数字位数五万位是不行的,因此要把数据放入字符串自行模拟逢十进一
  • 开vector容器是因为系统中有自带的插入函数可以不用自己写循环来遍历

过程解析

	for(int i=a.size()-1;i>=0;i--)
	{
		A.push_back(a[i]-'0');//加入a 中为1 2 3  A中为 3 2 1 
	}
	for(int i=b.size()-1;i>=0;i--)
	{
		B.push_back(b[i]-'0');//倒序放入,进位的时候就是升序了 
	}
  • 容器中的元素是逆序存放的,为了让进位的时候看起来更方便.假如说输入 123 456,存放在容器A,B分别就是321 654
  • 这里的a[i]-'0'意思是把存入字符串的字符转化为数字

高精度函数加减模拟

vector<int> add(vector<int> &A,vector<int> &B)//值传递的话会更快,进函数不用拷贝 
{
	vector<int> C; 
	int t=0;//进位
	for(int i=0;i<A.size()||i<B.size();i++)
	{
		if (i<A.size())t+=A[i];
		if (i<B.size())t+=B[i];//t把A,B当前位数和进位相加 
		
		C.push_back(t%10);//如果t大于10 逢十进一 然后加入到容器C
		t/=10;//加入说t=11,那么逢十进一 
	 } 
	 if(t)C.push_back(1);
  • 函数t首先把A,B当前位的数字相加,如果相加大于10,那么就要进位1,t%10的意思是:如果在这位是9+9 那么当前位保留8,进1
  • C容器存8,t=18,18/10=1,进位1保留到下一次相加.
  • 假如输入样例是985 ,34,因为是逆序存放数组,次外层进入循环,由于最内层5+4<=0,因此t初始为0,8+3=11,当前位保留1,进1,此时数组中是91,然后最外层进入循环9+1=10,10%10=0,因此 当前位插入0,10/10=1,t=1退出循环,此时数组中是910,最后if(t)C.push_back(1);判断最高位的自增.再插入1,此时数组中是9101,遍历的时候逆序输出就是答案了.

源代码

#include<bits/stdc++.h>
using namespace std;
string a,b;
vector<int>A,B;
//写一个高精度加法,容器A加容器B
vector<int> add(vector<int> &A,vector<int> &B)//值传递的话会更快,进函数不用拷贝 
{
	vector<int> C; 
	int t=0;//进位
	for(int i=0;i<A.size()||i<B.size();i++)
	{
		if (i<A.size())t+=A[i];
		if (i<B.size())t+=B[i];//t把A,B当前位数和进位相加 
		
		C.push_back(t%10);//如果t大于10 逢十进一 然后加入到容器C
		t/=10;//加入说t=11,那么逢十进一 
	 } 
	 if(t)C.push_back(1);//补充最高位的进位 
	 //因为每次进位都是在循环立案增加的,因此最高位进位加不上 
	 return C;//注意,C也要逆序输出,因为高位在后 
 } 
int main()
{
	cin>>a>>b;
	for(int i=a.size()-1;i>=0;i--)
	{
		A.push_back(a[i]-'0');//加入a 中为1 2 3  A中为 3 2 1 
	}
	for(int i=b.size()-1;i>=0;i--)
	{
		B.push_back(b[i]-'0');//倒序放入,进位的时候就是升序了 
	}
	auto C=add(A,B);//此时的auto 就是vector <int> 类型 
	//遍历容器 
	for(int i=C.size()-1;i>=0;i--)
	{
		cout<<C[i];//容器除了这么遍历还可以用迭代器,写起来会麻烦一点 
	}
	return 0;
}

1.2 高精度减法

给定两个正整数(不含前导 00),计算它们的差,计算结果可能为负数。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的差。

数据范围

1≤整数长度≤1051≤整数长度≤105

输入样例:
32
11
输出样例:
21

算法实现步骤

首先还是定义两个字符串然后把字符串里的数值转移到容器中

比较A数和B数的大小

一定是大数减去小数,这样能节省许多边界判断,因此定义了cmp函数

cmp函数

首先比较两个字符串的长度,如果长度相同就从高位往下比较位数哪个更大

if (a.size()!=b.size())return a.size()>b.size();//如果a长于b就返回1

其中我定义的cmp函数是这样的:

if (cmp(A,B))//A>B的时候是1
{
    //A-B 
}
else
{
    //B-A
}

sub函数

定义的sub函数用于A-B,其中A>B

先定义一个容器C用于放答案,然后设定一个循环让每一位都相减

t=A[i]-t;t是借位的意思

是每次进行运算之前都检查一下有没有借位,8-9时就需要借位,此时t=1,不需要的时候t=0

这行语句在赋值了A的那一位的同时处理了上一次运算的借位情况,因此接下来是t-=B[i];模拟了A的某位-B的某位的情况,得到的值就是t

此时t有两种情况

  1. t>=0
  2. t<0

但是可以用(t+10)%10归于一种情况

将t此时的值插入答案容器C中后,就需要判断这一轮需不需要借位了

if (t>=0)t=0;
else t=1;//往前面借一位 

如果需要借位的话t=1不需要的话t=0

去除前导0

比如说123-34答案容器C中会得到980,那么这种情况需要去除后面多出来的0

可以巧妙的使用:while(C.size()>1&&VC.back()==0)C.pop_back();来解决

意思是,当答案容器长度不小于1(即为0的情况),同时容器末尾为0时,去除0;

最后逆序输出答案就完事了

#include<bits/stdc++.h>
using namespace std;
string a,b;
vector<int>A,B;

bool cmp(vector<int>&A,vector<int>&B)//先比较位数,然后比较高位的大小 
{
	if (a.size()!=b.size())return a.size()>b.size();//如果a长于b就返回1 
	//如果a和b长度相同就逐个比较高位
	for(int i=a.size()-1;i>=0;i--) //因为是反着存的,所以需要从后往前比较 
	{
		if (A[i]!=B[i])return A[i]>B[i];
	}
	return true;//循环结束是两个数相同的情况 符合A>=B 
}

//a-b运算 
vector<int> sub(vector<int> &A,vector<int> &B)//此时,A>B,因为就算原先小于也调整过顺序了 
{
	int t=0;//t表示进位 
	vector<int> C;
	for (int i=0;i<A.size();i++)//001 09 0 1 0
	{
		t=A[i]-t;
		if(i<B.size())//如果B已经没有位数了例如123-34,b的位数有可能会被提前消耗完毕 
		{
			t-=B[i];
		} 
			//此时相当于A[i]-B[i],t可能大于0也可能小于0
			C.push_back((t+10)%10); 
			if (t>=0)t=0;
			else t=1;//往前面借一位 
	}
	//去除前导0  比如说123-34会算出980,那么这种情况需要去除后面多出来的0 
	while(C.size()>1&&C.back()==0) C.pop_back();
	return C;
}



int main()
{
	cin>>a>>b;
	//两个字符串逆序放入容器
	for (int i=a.size()-1;i>=0;i--)
	{
		A.push_back(a[i]-'0');
	}	
	for(int i=b.size()-1;i>=0;i--)
	{
		B.push_back(b[i]-'0');
	}
	
	//如果A>B A-B
	//A<B -(B-A)
	if (cmp(A,B))//比较下来如果A>=B的话是1
	{
		auto C=sub(A,B);
		//输出 
		 for(int i=C.size()-1;i>=0;i--)cout<<C[i];
	 } 
	 else
	 {
	 	cout<<'-';
	 	auto C=sub(B,A);
		//输出 
		 for(int i=C.size()-1;i>=0;i--)cout<<C[i];
	 }	 
	return 0;
 } 

1.3 高精度乘法

1.3.1 高精度乘低精度

给定两个非负整数(不含前导 00) A和 B,请你计算 A×B 的值。

输入格式

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式

共一行,包含 A×B 的值。

数据范围

1≤A的长度≤1000001
0≤B≤100000

输入样例:
2
3
输出样例:
6

图例模拟:
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
string a;
int b;
vector<int> A;

vector<int> mul(vector<int> &a,int b)
{
	vector<int> C;
	int t=0;
	for (int i=0;i<A.size()||t;i++)
	{
		if (i<A.size())t+=A[i]*b;
		C.push_back(t%10);//188 *81 648进64 712进71 152进15 
		//如果循环条件只有i<A.size()的话就已经结束了 ,接下来的部分是t还没有进完位数
		//15进1,1进1,t=0结束 
		t/=10;//进位 
	}
	//避免前导0 比如说12345 *0=00000
	while(C.size()>1&&C.back()==0) C.pop_back(); 
	return C;
}

int main()
{
	cin>>a>>b;
	for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
	auto C=mul(A,b);
	//输出
	for(int i=C.size()-1;i>=0;i--)
	{
		cout<<C[i];
	 } 
	return 0;
}
1.3.2 高精度乘高精度

注解1:使用两层循环计算 A[i] 与 B[j] 的乘积,并将结果累加到 C[i+j]。为什么是C[i+j]?

这个乘法算法中,我们使用两层循环来遍历两个大数 AB 的每一位,并计算它们的乘积。

考虑两个数字的乘法:

cssCopy code    A = [a3, a2, a1, a0]
 B = [b2, b1, b0]

我们需要计算:

cssCopy code
 C = A * B

结果 C 的每一位都是由 AB 中某两位的乘积决定的。例如:

  • C[0] 是由 a0 * b0 决定的。
  • C[1] 是由 a1 * b0a0 * b1 的和决定的。
  • C[2] 是由 a2 * b0a1 * b1a0 * b2 的和决定的。
  • C[3] 是由 a3 * b0a2 * b1a1 * b2a0 * b3 的和决定的。

在这里,i+j 代表了 A[i]B[j] 在结果 C 中对应的位置。因此,我们累加每一位乘积到 C[i+j]。这种方式可以确保我们正确地计算出每一位的乘积,并将它们放置在正确的位置。

图例:

#include<bits/stdc++.h>
using namespace std;
string a,b;
vector<int>A,B;

//高精乘高精是运算和进位分开的,高精成低精是一边运算一边进位的 
vector<int> mul(vector<int>&A,vector<int>&B) 
{
//相乘的时候从低位开始乘 
	vector<int>C(A.size()+B.size());//开位数因为后面会有覆盖 
	for(int i=0;i<A.size();i++)
	{
		for(int j=0;j<B.size();j++)
		{
			C[i+j]+=A[i]*B[j];//见注解1 
		}
	}
	//有前导零的原因是因为初始化数组的时候vector<int>C(A.size()+B.size()),可能用不到那么多位数 
	//如果是12*12 C中是4 4 1 0 
	//如果是99*99 C中是81 162 81 0 
	//如果是12345*0 会是0 0 0 0 0 
//	for(int i=0;i<C.size();i++)printf("%d ",C[i]); 
//	cout<<endl;
	//处理进位
	int t=0;
	for(int i=0;i<C.size()||t;i++)//判断条件是因为t在运算完之后会有几个还来不及进位。当 t 大于零时,我们继续进行处理,直到 t 为零为止。
	{
		if(i<C.size())t+=C[i];
		//C.push_back(t%10);
		C[i]=t%10;
		t/=10;
	 } 
	//因为开的位数会多,所以要去除前导零
	//去除前导零
	while(C.size()>1&&C.back()==0)C.pop_back();
	return C;
}


int main()
{
	cin>>a>>b;
	//逆序
	for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
	for(int i=b.size()-1;i>=0;i--)B.push_back(b[i]-'0');
	
	auto C=mul(A,B);
	
	//输出
	for(int i=C.size()-1;i>=0;i--)printf("%d",C[i]); 
	return 0;
}

1.4 高精度除法

给定两个非负整数(不含前导 00) A,B,请你计算 A/B的商和余数。

输入格式

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式

共两行,第一行输出所求的商,第二行输出所求余数。

数据范围

1≤A的长度≤100000
1≤B≤10000
B一定不为 0

输入样例:
7
2
输出样例:
3
1

图例:
在这里插入图片描述

一些提示:

代码中的r是通过改变地址而改变了其中的参数。s

#include<bits/stdc++.h>
using namespace std;
vector<int>A;
string a;
int b;

//除法运算
vector<int> div(vector<int> &A,int &b,int &r)
{
	//除法是从高位开始除的
	 vector<int> C;
	 r=0;
	 for(int i=A.size()-1;i>=0;i--)
	 {
	 	r=r*10+A[i];//r是被除数.r=1,12,13比如说123/11 第一步1/12=0 第二步12/11余1 
	 	C.push_back(r/b);
	 	r%=b;
	 }
	 reverse(C.begin(),C.end());//和加减乘统一 
	 //去除前导0 否则 运算10/9会输出 01 余1 
	 while(C.size()>1&&C.back()==0)C.pop_back();
	 return C;
	 
 } 

int main()
{
	cin>>a>>b;
	//逆序放入容器
	for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
	//模拟除法运算(需要返回余数)
	int r=0;
	auto C=div(A,b,r);//r通过地址改变里面的值最后输出出来
	//输出(正序) 
	for(int i=C.size()-1;i>=0;i--)
	cout<<C[i];
	cout<<endl<<r<<endl;
	return 0;
}
  • 30
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值