高精度加减乘除——C++实现

news2024/11/25 18:52:20

每日一句:每天早上醒来时,我们有两个简单的选择:回头去睡,继续做梦。或者起身去追逐梦想。

高精度加减乘除

  • 前言
  • 一、高精度加法
    • 1.基本思路
    • 2.分步讲解
      • 2.1输入字符数字
      • 2.2把字符数字转换为数字
      • 2.3实现add函数
    • 3.完整代码
  • 二、高精度减法
    • 1.基本思路
    • 2.分步讲解
      • 2.1~2.2
      • 2.3cmp函数
      • 2.4sub函数实现
      • 2.5去除前导零
    • 3.完整代码
  • 三、高精度乘法
    • 1.基本思路
    • 2.分布讲解
      • 2.1mul函数实现
    • 3.完整代码
  • 四、高精度除法
    • 1.基本思想
    • 2.分步讲解
      • 2.1输入操作
      • 2.2div函数实现
    • 3.完整代码


前言

学高精度加减乘除有什么用呢?当你要算的加减法没有超出数据类型最大的long long的范围时,当然不需要用到高精度,当你计算的数据过于大的时候呢?这个时候,就需要高精度算法了,利用**数字字符-‘0’**可以得到数字。

一、高精度加法

1.基本思路

高精度加法就是模拟小学学的加法操作,在这里插入图片描述
相信这个运算对大家来说是特别简单的,尽管有进位,那么,我们怎么用代码去实现呢?

2.分步讲解

2.1输入字符数字

	string a, b;
	vector<int>A, B;
	cin >> a >> b;

将长整数当成字符进行输入,那为什么不直接用数组存数字呢?当你给数组输入数字的时候,你需要一位一位的输入,利用字符可以直接输完,再用数组把数字存起来就可以了。

2.2把字符数字转换为数字

先把代码给出来

	string a, b;
	vector<int>A, B;
	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');
	}


把字符1和字符0相减,差值刚好是1,这样就可以把1存进数组里,其他的数字也是这样的操作,为了把每位数都转换,可以利用for循环,但要注意,转换这一步是倒着存在数组里的,为什么呢?看下面的图,我们进行加减法的时候是说的一百二十三,如果不把数组倒着存,那么就会造成先把百位进行了加法,这样在进行有进位的计算时就会出现错误。
在这里插入图片描述

	for (int i = 0; i < a.size(); i++)
	{
		A.push_back(a[i] - '0');
	}
	for (int i = 0; i < b.size(); i++)
	{
		B.push_back(b[i] - '0');
	}

在这里插入图片描述

在这里插入图片描述

这样就会造成结果错误,当然个人觉得把代码改改,改成高位在前面的也不是不能写但会比较麻烦(没有尝试)各位可以自行测试一下。

2.3实现add函数

实现add函数,也是比较关键的一步,在这个函数里面,又定义了一个C和t(t表示的就是A[i]加B[i]之后的值),在这个C里面,存的就是答案,只不过要注意这个答案在C里面也是倒序的,在输出的时候,要注意取值问题。

	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];
		}
		C.push_back(t % 10);
		t /= 10;
	}

这里要注意循环条件,一定要小于A的长度或者小于B的长度,满足二者之一即可,因为前面的代码中并没有专门去进行A,B长度的比较。比较一下也很简单。

if(A.size() < B.size())
{
	return add(B,A);	
}

这样写的话,下面的for循环的循环条件只需要小于A就行了。
但是这样考虑的情况并不完美,如果高位又进位了,怎么办?,在这个循环里面,并没有解决这个问题的步骤,注意:在加法中进位,最多进1位,所以,我们可以用if来判断t为真假就可以了。

	if (t)
	{
		C.push_back(t);
	}

这就是完整的高精度加法操作了。

3.完整代码

#include <iostream>
#include <vector>
using namespace std;

vector<int> add(vector<int>& A, vector<int>& B)//这里的&是引用的意思,在这里不过多介绍
{
	int t = 0;
	vector<int> C;
	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];
		}
		C.push_back(t % 10);
		t /= 10;
	}
	if (t)
	{
		C.push_back(t);
	}
	return C;
}

int main()
{
	string a, b;
	vector<int>A, B;
	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 = add(A, B);

	for (int i = C.size() - 1; i >= 0; i--)
	{
		cout << C[i];
	}
	return 0;
}

例题详见acwing791.高精度加法

二、高精度减法

1.基本思路

高精度减法和高精度加法的思路其实都差不多,都是最基本的运算法则。
在这里插入图片描述

2.分步讲解

2.1~2.2

	string a, b;
	vector<int>A, B;
	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');
	}

这个代码的思路跟高精度加法的思路是一样的,就不在细说了。

2.3cmp函数

要注意一个问题就是要相减的两个数,谁大,谁小,这个时候就要额外写一个用于比较大小的函数。这个函数能放止出现小数-大数的情况,就比如111 - 888,可以先进行888 - 111的运算,先输出-,在输出777,这样不也是-777。
代码

bool cmp(vector<int>& A, vector<int>& B)
{
	if (A.size() != B.size())
	{
		return A.size() > B.size();
	}

	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的长度去分辨谁大谁小,当A和B的长度相等的时候,就直接从数的最高位,也就是A,B的最后一个元素去进行比较,若全部符合,则返回true,走到最后一步的时候,也说明了两个数字是相等的。

2.4sub函数实现

vector<int> sub(vector<int>& A, vector<int>& B)
{
	int t = 0;
	vector<int> C;
	for (int i = 0; i < A.size(); i++)
	{
		t += A[i];
		if (i < B.size())
		{
			t -= B[i];
		}
		C.push_back((t + 10) % 10);
		if (t < 0)
		{
			t = -1;
		}
		else
		{
			t = 0;
		}
	}
	while (C.size() > 1 && C.back() == 0)
	{
		C.pop_back();
	}
	return C;
}

在cmp函数里已经比较过大小,所以,在这个减法函数里,A就是最大的数字,直接利用i<A.size()去遍历是可以的,A遍历完,B一定遍历完,A没遍历完,B可能遍历完,所以在对B进行减法操作时,要加上判断条件,判断B是否走到头。
C.push_back((t + 10) % 10);
这一步为什么要让t+10,再去%10呢?,在减完之后,t万一是个负数呢?加10%10的结果是0,相当于t+一个0,即使t是负数,加了10也不会影响结果。t在这里也可以借位,如100 - 69:(0 + 10 - 9) % 10 = 1;结果也应该输出1.
在这里插入图片描述

		if (t < 0)
		{
			t = -1;
		}
		else
		{
			t = 0;
		}

看这里,t<0,t就等于-1,然后回到第一步,t += A[i];,这不就是借位的实现吗?

2.5去除前导零

	while (C.size() > 1 && C.back() == 0)
	{
		C.pop_back();
	}

去除前导零是放止出现下面图片里的情况
在这里插入图片描述
有前导零的情况就是,位数大于1位,最后一位(最后一位是高位)必须得是0。

3.完整代码

#include <iostream>
#include <vector>
using namespace std;

bool cmp(vector<int>& A, vector<int>& B)
{
	if (A.size() != B.size())
	{
		return A.size() > B.size();
	}

	for (int i = A.size() - 1; i >= 0; i--)
	{
		if (A[i] != B[i])
		{
			return A[i] > B[i];
		}
	}

	return true;
}

vector<int> sub_(vector<int>& A, vector<int>& B)
{
	int t = 0;
	vector<int> C;
	for (int i = 0; i < A.size(); i++)
	{
		t += A[i];
		if (i < B.size())
		{
			t -= B[i];
		}
		C.push_back((t) % 10);
		if (t < 0)
		{
			t = -1;
		}
		else
		{
			t = 0;
		}
	}
	while (C.size() > 1 && C.back() == 0)
	{
		C.pop_back();
	}
	return C;
}

int main()
{
	string a, b;
	vector<int>A, B;
	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');
	}
	if (cmp(A, B))
	{
		auto C = sub_(A, B);
		for (int i = C.size() - 1; i >= 0; i--)
		{
			cout << C[i];
		}
	}
	else
	{
		auto C = sub_(B, A);
		cout << "-";
		for (int i = C.size() - 1; i >= 0; i--)
		{
			cout << C[i];
		}
	}
	return 0;
}

例题详见acwing792.高精度减法

三、高精度乘法

1.基本思路

高精度乘法,用的还是最基本的运算思维,刚开始的思路跟加法差不多,先输入字符数字,然后转换为数字,进入mul函数,实现乘法操作,然后去除前导零。
在这里插入图片描述

2.分布讲解

2.1mul函数实现

前面思路和高精度加法思路差不多,详细看高精度加法2.1~2.2。

vector<int> mul(vector<int>& A, int& b)
{
	vector<int>C;
	int t = 0;
	for (int i = 0; i < A.size(); i++)
	{
		t += A[i] * b;
		C.push_back(t % 10);
		t /= 10;
	}
	if (t)
	{
		C.push_back(t);
	}
	while (C.size() > 1 && C.back() == 0)
	{
		C.pop_back();
	}

	return C;
}

高精度乘法,在这里,用的是一个字符数字转化为数组,然后去乘一个int类型的数,没有用两个字符数字。
在这个函数里,只需要把A里面的每位数都b就能得到结果,中间的进位用t去表示,t%10,可以得到本位的数,t/10得到进位的数,然后在t += A[i] * b;这一步中,把进位的数字在加上去,直到循环结束,但别忘了,循环结束的时候,t可能还为真,这个时候就需要判断t是否为真,为真,就把t加在C的后面;为假则进行下一步。
去重,乘法为什么还要去重?因为会有0
12345的情况出现,这种情况不去重的话会出现00000的情况,所以要进行去重操作。

3.完整代码

#include <iostream>
#include <vector>
using namespace std;

vector<int> mul(vector<int>& A, int& b)
{
	vector<int>C;
	int t = 0;
	for (int i = 0; i < A.size(); i++)
	{
		t += A[i] * b;
		C.push_back(t % 10);
		t /= 10;
	}
	if (t)
	{
		C.push_back(t);
	}
	while (C.size() > 1 && C.back() == 0)
	{
		C.pop_back();
	}

	return C;
}

int main()
{
	string a;
	int b;
	vector<int>A;
	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;
}

详见例题acwing793.高精度乘法

四、高精度除法

1.基本思想

利用字符数字转化为数字,转化的同时把数字倒着存进数组A里,让A里的数去除要除的数,结果存在数组C里,然后把C输出。

2.分步讲解

2.1输入操作

	string a;
	int r ;//在这里,r表示的是余数
	int b;//b表示的是除数
	vector<int>A;
	cin >> a >> b;
	for (int i = a.size() - 1; i >= 0; i--)
	{
		A.push_back(a[i] - '0');
	}

这个操作和高精度加法一样。

2.2div函数实现

	vector<int> C;
	for (int i = A.size() - 1; i >= 0; i--)
	{
		r =(r*10 + A[i]) ;
		C.push_back(r / b);
		r %= b;
	}
	reverse(C.begin(), C.end());
	while (C.size() > 1 && C.back() == 0)
	{
		C.pop_back();
	}

因为对A的最高位开始处理,因为在前面把小位放在了A的前面,高位放在了后面,所以要i=A.size() - 1;

r =(r*10 + A[i]) ;

将上次的余数*10在加上当前位的数字,便是该位需要除的被除数,

C.push_back(r / b);

把商放在这里,

r %= b;

除完当前位的余数。

在除法操作中,是高位到低位的运算,所以C的前导零都在vector的前面,而vector是有pop_back()函数的,这个函数只能删除最后一位,所以要用reverse进行逆置,在进行去除前导零的操作。

	reverse(C.begin(), C.end());
	while (C.size() > 1 && C.back() == 0)
	{
		C.pop_back();
	}

3.完整代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int r;

vector<int> div(vector<int>& A, int& b)
{
	vector<int> C;
	for (int i = A.size() - 1; i >= 0; i--)
	{
		r =(r*10 + A[i]) ;
		C.push_back(r / b);
		r %= b;
	}
	reverse(C.begin(), C.end());
	while (C.size() > 1 && C.back() == 0)
	{
		C.pop_back();
	}

	return C;
}

int main()
{
	string a;
	int b;
	vector<int>A;
	cin >> a >> b;
	for (int i = a.size() - 1; i >= 0; i--)
	{
		A.push_back(a[i] - '0');
	}
	auto C = div(A, b);

	for (int i = C.size() - 1; i >= 0; i--)
	{
		cout << C[i];
	}
	cout << endl << r;
	return 0;
}

详见例题acwing794.高精度除法
以上就是高精度加减乘除,希望对大家有帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/84114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Python计算机毕业设计大学生网络安全题库系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

Linux进程通信

写在前面 今天主要的任务就是知道什么是进程通信?进程通信是如何实现的?前面我们学习了基础IO,再往前看又学习进程的相关的概念,那么今天我们通过进程的通信来把他们用起来.这个话题挺重要的,但是没有前面的大. 进程通信 "通信"这个单词很好理解,就是两个或者多…

Codon

又搬来了一个框架 并没用过啊 说着比c还厉害~ 大伙谁 研究过呢? 希望不是和咱们的中药一样~~ 众所周知&#xff0c;Python 是一门简单易学、具有强大功能的编程语言&#xff0c;在各种用户使用统计榜单中总是名列前茅。相应地&#xff0c;围绕 Python&#xff0c;研究者开发了…

Vector-常用CAN工具 - CANoe入门到精通_05

CAPL Test Module 在“Vector-常用CAN工具 - CANoe入门到精通”的第4/4篇中介绍了作为Server端的Network Node节点以及相应的一些常用函数&#xff0c;今天我们来介绍下当前依然有很多人在用的自动化脚本开发编译器 - CAPL Test Module&#xff0c;这个基本能满足单个功能模块…

KingbaseES V8R6备份恢复案例之---sys_waldump解析wal日志PITR恢复

​案例说明&#xff1a; 复现用户删除表(drop table)误操作&#xff0c;通过wal日志解析找到误操作时间点&#xff0c;执行基于时间点的恢复(PITR)。适用版本&#xff1a; KingbaseES V8R6 一、模拟业务现场操作 1、查看当前对象信息 prod# \dList of relationsSchema | …

R语言逻辑回归预测分析付费用户

对于某企业新用户&#xff0c;会利用大数据来分析该用户的信息来确定是否为付费用户&#xff0c;弄清楚用户属性&#xff0c;从而针对性的进行营销&#xff0c;提高运营人员的办事效率。 相关视频&#xff1a;R语言逻辑回归&#xff08;Logistic回归&#xff09;模型分类预测病…

javaScript内存管理及监控

1.1 内存定义 内存由可读写单元组成&#xff0c;表示一片可操作空间&#xff0c;开发者主动申请空间、使用空间、释放空间。内存主要存储变量等数据&#xff0c;局部变量当程序执行结束&#xff0c;且没有引用的时候就会随着消失&#xff0c;全局对象会始终存活到程序运行结束。…

【简单项目实战】用C++实现学生成绩管理系统

目录 ●功能介绍 ●案例 ●代码展示 ●结果展示 ●功能介绍 用 C设计一个程序&#xff0c;能提供下列功能: 1. 录入学生成绩信息。按照学号&#xff0c;姓名&#xff0c;语文&#xff0c;数学&#xff0c;英语的格式录入学生的成绩。 2.展示目前录入学生的成绩信息。以…

MeterSphere使用mock基础

目录 一、添加mock数据 1、进入页面添加 2、 添加单个mock 3、添加多个mock数据 二、运行mock 1、选择设置接口的TEST 2、选择mock环境 3、设置定义的mock参数运行 一、添加mock数据 1、进入页面添加 在接口定义页面&#xff0c;按下图1-2-3顺序添加 2、 添加单个mock…

[附源码]Nodejs计算机毕业设计基于JAVA人事管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

如何利用TL431设计一个可调电压源

TL431是一个三脚电压可控的稳压器件&#xff0c;常用的封装有TO-92&#xff0c;SOT-23&#xff0c;SOT-89&#xff0c;电路符号是这个&#xff0c; TL431常被用在参考电压/基准电压电路&#xff0c;用来替代稳压管 其中1脚是reference,2脚是Anode&#xff0c;3脚是Cathode TL4…

基于微信小程序的校园二手交易-计算机毕业设计

项目介绍 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;校园二手交易被用户普遍使用&#xff0c;为方便用户能…

最新版网络组件包:Rebex Total Pack for .NET

Rebex Total Pack for .NET 组件包&#xff1a; Rebex 的所有 .NET 组件都在一个包中&#xff1a;SFTP、FTP、HTTPS、IMAP、POP3、SMTP、EWS、SNTP/Time/Daytime、Mail、MSG、TLS、SSH Shell、Telnet、终端仿真、安全、Syslog、WebSocket、 ZIP 压缩&#xff0c;SFTP/SSH 服务…

Java之final相关内容详解【面试题】

1、final关键字除了修饰类之外&#xff0c;还有哪些用法呢&#xff1f; &#xff08;1&#xff09;final修饰的变量&#xff0c;一旦赋值&#xff0c;不可重新赋值&#xff1b; &#xff08;2&#xff09; 如果引用为引用数据类型&#xff0c;比如对象、数组&#xff0c;则该对…

生成模型(二):VAE

自动编码器的发明是为了重建高维数据&#xff08;这可能不是变异自动编码器的真实情况&#xff09;。一个很好的副产品是降维&#xff1a;瓶颈层捕获了一个压缩的潜在编码。这样的低维表示可以作为各种应用中的嵌入向量&#xff08;如搜索&#xff09;&#xff0c;帮助数据压缩…

计算机研究生就业方向之大厂销售(营销)

我一直跟学生们说你考计算机的研究生之前一定要想好你想干什么&#xff0c;如果你只是转码&#xff0c;那么你不一定要考研&#xff0c;至少以下几个职位研究生是没有啥优势的&#xff1a; 1&#xff0c;软件测试工程师&#xff08;培训一下就行&#xff09; 2&#xff0c;前…

世界杯---人生就是一届又一届世界杯

注意&#xff1a;下面有视频看到文章会有声音&#xff0c;如果打扰到您非常抱歉&#xff0c;视频在文章最下面&#xff0c;还望观众老爷们不要在意&#xff0c;蟹蟹理解~ &#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &a…

OTP语音芯片是用什么软件来编程,以及如何烧录的?

目录 OTP语音芯片的开发环境&#xff1a; 也就是一般的客户想自己开发&#xff0c;基本不可能了&#xff0c;因为前期的培训成本、工具成本都是比较高的 OTP语音芯片的烧录方法&#xff1a; 第1步&#xff0c;是开发编译好程序之后&#xff0c;生成了对应的bin文件&#xf…

15、Redis集群

文章目录15、Redis集群15.1 问题15.2 什么是集群15.3 删除持久化数据15.4 制作6个实例15.4.1 配置基本信息15.4.2. redis cluster配置修改15.4.3. 修改好redis6379.conf文件&#xff0c;拷贝多个redis.conf文件15.4.4 使用查找替换修改另外5个文件15.4.5 启动6个redis服务15.5 …

MySQL innodb引擎架构分析- Double Write Buffer

文章目录系列文章目录前言一、Double Write Buffer是什么&#xff1f;二、Double Write Buffer步骤步骤对性能的影响总结系列文章目录 1. MySQL innodb引擎架构分析-Buffer Pool 2. MySQL innodb引擎架构分析-Redo log 3. MySQL innodb引擎架构分析- Double Write Buffer 前言…