C++处理大数问题/高精度问题,看这就够了

写在前面:这里是小王成长日志,一名在校大学生,想在学习之余将自己的学习笔记分享出来,记录自己的成长轨迹,帮助可能需要的人。欢迎关注与留言。

0.导入

问题背景

在做算法题时,我们时常会遇到正常的类型进行不了的运算,如两个long long int 相乘并对某个数取模,有时我们可以使用快速幂和龟速乘解决。
但有的题目直接给的是n位的整数,比如下面这道题-洛谷传送门,给出的数据最大已经达到了10000多位,直接使用int,long long 之类的数据必爆无疑。
因此是时候祭出我们的大数处理方法了,大数,就是指利用已有的类型无法进行保存和运算的数字。
其实大数处理,就是利用字符串一位一位保存我们的大数,并且模拟正常的加减乘除过程进行大数的运算。
接下来,我们将一一讨论大数的加减乘除,其中加减乘较简单,除法相较而言难于理解,保持耐心,我默认你已经理解字符串和字符数组的概念,我们开始吧。

题目描述
高精度减法。
输入格式
两个整数 a,ba,b(第二个可能比第一个大)。
输出格式
结果(是负数要输出负号)。
输入输出样例
输入
2
1
输出
1
说明/提示
20 20 20% 数据 a , b a,b a,b 在 long long 范围内;
100 100 100% 数据 0 < a , b ≤ 1 0 10086 0<a,b≤10^{10086} 0<a,b1010086

大数存储

想要对大数进行运算,第一个遇到的如何存储大数,对于这个问题,一般我们采用的都是数组,即利用一个整形数组存储一个数字,如下:
在这里插入图片描述
首先我们定义一个整形数组,再将这个大数一位位的存入这个数组中。
注意:

  1. 一般我们都是翻转保存的,即低位在前,高位在后(个位存在a[0]或a[1]处,这是为了之后模拟运算的时候方便)。
  2. 有的时候我们可以将数组索引0的位置空出来存储大数的长度,而不用我们的模拟函数去返回大数运算结果的长度,但是在本文中并没有这么实现,但是这也是一种不错的想法,值得一试。

大数运算核心思想

大数运算,核心思想就是模拟运算,加减乘都是直接模拟小学学的数学,除法有些特殊,使用的是减法实现(例如4/2就可以表示成4-2-2)

以下是一段除法与减法的关系,以供参考:

除法与减法之间的关系:
1、能够整除的除法
除法可以看作连续减去相同数的减法;被除数就是被减数,除数就是相同的减数,连减的最多次数就是商。
2、不能整除的除法
除法可以看作连续减去相同数的减法;被除数就是被减数,除数就是相同的减数,连减的最多次数就是商,除法的余数就是减法的最后结果数值。

具体的模拟过程在各种运算中会有讲解,这里先知道是模拟运算即可。

以下的大数运算除了除法我都没有抽象出函数来,但在理解后这是非常简单的,不会影响食用。

1.大数加法

对于加法,很明显,从低位开始加,满10 进1 模拟很简单

//这里a[] b[] 是存储要运算的两个大数 max是ab两数中较大的一个的位数 c[] 存储运算结果,并且abc所有未被使用过的位置都被初始化为0
	for(i=0;i<max;i++)
	{
   
		c[i]+=a[i]+b[i];
		if(c[i]>=10){
   //进位处理
			c[i+1]+=1;//进10位 
			c[i]%=10;//留下个位 
		}
	}
	
	//处理进位也可以单独拿出做 - 可以手动模拟一下两种方法
	/*for(i=0;i<max;i++){
		if(c[i]>=10){
			c[i+1]+=1;//进10位 
			c[i]%=10;//留下个位 
		}
	}*/

完整代码

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

int main(){
   
	
	//读入两个大数 
	string num1,num2;//字符串 利用字符数组存也是可以的 
					// 但是注意数组长度需要足够 很多大数题目数字长度都是上万的
	cin>>num1>>num2;
	
	//分别获取位数并将每一位存入整形数组中 
	int n=num1.length(),m=num2.length();//length()函数用于获取存储字符串长度
	int max= m>n?m:n +1;//两个数相加  位数不会超过较大的数的位数+1 
	int a[max],b[max],c[max];//每一位都初始化为0 
	//int a[max]={0},b[max]={0},c[max]={0};//每一位都初始化为0 
	/****按理来说如上的初始化是允许的,但是有的编译器
	   可能初始化出错,所以最后手动出初始化一下,或者定义全局变量了事**/
	int i,j;
	for(i=0;i<max;i++)//初始化 
		a[i]=0; 
	for(i=0;i<max;i++)//初始化 
		b[i]=0; 
	for(i=0;i<max;i++)//初始化 
		c[i]=0; 	
		
	//num1 - n位 - 将num1字符串存储的大数翻转存储(a[0]存储个位,a[1]存储十位)到int数组a中
	for(i=0,j=n-1;i<n;i++,j--)
		a[i]=num1[j]-'0';
	//num2 - m位 
	for(i=0,j=m-1;i<m;i++,j--)
		b[i]=num2[j]-'0';
	
	/*********上面都是利用数组储存大数,下面开始模拟大数加法*************/

	for(i=0;i<max;i++)
	{
   
		c[i]+a[i]+b[i];//若需要在计算的同时进行进位处理,需要写成+=
		if(c[i]>=10){
   //进位处理
			c[i+1]+=1;//进10位 
			c[i]%=10;//留下个位 
		}
	}
	
	//处理进位也可以单独拿出做 - 可以手动模拟一下两种方法
	/*for(i=0;i<max;i++){
		if(c[i]>=10){
			c[i+1]+=1;//进10位 
			c[i]%=10;//留下个位 
		}
	}*/
	
	i=max-1;
	while(c[i]==0)//去除答案数组c中高位上的0
		i--;
	
  • 182
    点赞
  • 358
    收藏
    觉得还不错? 一键收藏
  • 42
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值