高精度算法——数组模拟(加、减、乘、除)

目录

1、高精度算法是什么

2、高精度运算易错点

3、高精度加法

4、高精度减法

5、高精度乘法

1、两个高精度整数相乘

2、阶乘 —(n个低精度整数相乘,最终结果是高精度整数) 

3、 Hanoi双塔问题——2*(pow(2,n)-1)——暴力的话会爆内存

6、高精度除法

1、高精度÷低精度


1、高精度算法是什么

  • 在c++中int、long long int等存储方式只能计算十几位的整数运算,而当我们想要计算更多位时,就需要用到高精度算法。

  • 高精度算法:它是处理大数字的数学计算方法,在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除等运算。

思想:

  • 将这种大数字拆开,拆成一位一位的,这样可已输入位数很长的数,接下来将每一位取出,存入数组中 ,然后用一个数组去存储每个数字,最后再将数组进行相应的运算(加、减、乘、除、等)。

2、高精度运算易错点

高精度加法:

  1. 倒叙输入,倒序输出,但中间是正着运算;
  2. 相加之后的进位处理;

高精度减法:

  1. 考虑结果出现的正情况;
  2. 前导0的处理;
  3. 考虑减法的借位处理;

高精度乘法:

  1. 前导0的处理(0被相乘)!!!***容易被忽略***;
  2. 可以将乘法单个位数相乘再转化成加法的思想;
  3. 此时题目中没有涉及到负数的情况。如出现负数,只需考虑两个字符串第一位是否为负号,然后结尾特殊判断一下即可;

高精度除法:(高精度÷低精度)

  1. 输入、计算、输出、需要同时逆序或同时正序;
  2. 前导0的处理!!!***容易被忽略***;
  3. 不能考虑进位的情况!!

3、高精度加法

题目描述

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

输入格式

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

输出格式

共一行,包含所求的和。

数据范围

1≤整数长度≤100000;

输入样例:

12
23

输出样例:

35
  • 手动模拟——例如计算:567 + 28 = 595
  • 先个位相加: 7 + 8 = 15,所以结果的个位是5,向十位进 1
  • 再十位相加: 6 + 2 + 1(进位)= 9, 所以十位是 9,向百位进 0
  • 在百位相加: 5 + 0 = 5, 所以结果的百位是 5
  • 综上所述,计算结果为 595。

易错点:

  1. 一定要将数字进行倒叙输入,最后结果也是倒序输出,而中间的运算是正序运算。
  2. s1,s2两个字符串下标是从0开始的。
#include<iostream>
#include<algorithm>

using namespace std;
const int N = 1e5 + 10;

string s1, s2;
int a[N], b[N], c[N];

int main()
{
	cin >> s1 >> s2;
	int j = 1, k = 1;//a、b数组的下标都是从1开始的
	for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
	for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';

	int ma = max(s1.size(), s2.size());//记录最大长度
	int ans = 0;
	for (int i = 1; i <= ma; i++)
	{
		ans = ans + (a[i] + b[i]);
		c[i] = ans % 10;
		ans = ans / 10;
	}

	if (ans) c[++ma] = ans;//**一定要注意最后是否会向前进一
	for (int i = ma; i >= 1; i--)
	{
		cout << c[i];
	}
	return 0;
}

4、高精度减法

题目描述:

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

输入格式

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

输出格式

共一行,包含所求的差。

数据范围

1≤数长度≤100000

输入样例:

32
11

输出样例:

21

易错点:

  • 减法的借位处理

  • 相减为负数的处理

  • 前导0的处理!!!!****容易被忽略ke'yi****

#include<iostream>
#include<algorithm>

using namespace std;
const int N = 1e5 + 10;

string s1, s2;
int a[N], b[N], c[N], flag = 0;

int main()
{
	cin >> s1 >> s2;
	if (s1.size() < s2.size() || s1.size() == s2.size() && atoi(s1.c_str()) < atoi(s2.c_str()))
	//这个判断是用来s1和s2那个字符串更大的。atoi(s1.c_str())—将s1字符串转化成数字进行比较
	{
		flag = 1;
		swap(s1, s2);//保证s1始终是最大的字符串,同时做出正负的判断。
	}
	int j = 1, k = 1;//a,b下标从1开始
	for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
	for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';

	int ma = max(s1.size(), s2.size());//ma用来存最大长度的字符串个数
	for (int i = 1; i <= ma; i++)
	{
		if (a[i] - b[i] < 0)//错位相减
		{
			a[i] = a[i] + 10;
			a[i + 1] = a[i + 1] - 1;
		}
		c[i] = a[i] - b[i];
	}
	while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
	if (flag == 1) printf("-");//负数的判断
	for (int i = ma; i >= 1; i--)//
	{
		cout << c[i];
	}
	return 0;
}

5、高精度乘法

1、两个高精度整数相乘

题目描述

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

输入格式

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

输出格式

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

数据范围

1≤A的长度≤100000
0≤B≤10000;

输入样例:

2
3

输出样例:

6

易错点:

  • 前导0的处理(0被相乘)!!!***容易被忽略***;
  • 可以将乘法单个位数相乘再转化成加法的思想;
  • 此时题目中没有涉及到负数的情况,如出现负数,只需考虑两个字符串第一位是否为负号,然后结尾特殊判断一下即可。
#include<iostream>
#include<algorithm>

using namespace std;
const int N = 1e6 + 10;

string s1, s2;
int a[N], b[N], s[N], c[N];

int main()
{
	cin >> s1 >> s2;
	int j = 1, k = 1;
	for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
	for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';

	for (int i = 1; i <= s1.size(); i++)
	{
		for (int j = 1; j <= s2.size(); j++)
		{
			s[i + j - 1] += a[i] * b[j];//单个数组逐一相乘
		}
	}
	int ma = s1.size() + s2.size() - 1;//记录一下最高位数
	int ans = 0;
	for (int i = 1; i <= ma; i++)//高精度算法的核心
	{
		ans = ans + s[i];
		c[i] = ans % 10;
		ans = ans / 10;
	}
	if (ans) c[++ma] = ans;//考虑进位的情况
	while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
	for (int i = ma; i >= 1; i--)
	{
		cout << c[i];
	}
	return 0;
}

2、阶乘 —(n个低精度整数相乘,最终结果是高精度整数) 

题目描述:

输入一个正整数 N,输出 N 的阶乘。

输入格式
输入包含多组测试数据。

每组数据占一行,包含一个整数 N。

输出格式
每组数据输出占一行,输出 N 的阶乘。

数据范围
1≤N≤1000,
每个输入最多包含 100 组数据

输入样例:
 

4
5
15


输出样例:
 

24
120
1307674368000

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 1e6 + 10;
int n, a[N], ans, x, m, d;

int main()
{
	while (cin >> n)
	{
		a[0] = 1, d = 1;
		for (int i = 1; i <= n; i++)//从1开始一直乘到本数;
		{
			x = 0;
			for (int j = 0; j < d; j++)//几位就循环几次
			{
				ans = a[j] * i + x;//每一位乘上i,加上余数后所得的数
				a[j] = ans % 10;//把最后一位给数组,其他的向前进
				x = ans / 10;//把ans的最后一位数去掉
			}
			while (x != 0)//用while把c分配到各个高位
			{
				a[d++] = x % 10;//每进一位位数加一
				x = x / 10;
			}
		}

		for (int i = d - 1; i >= 0; i--)
		{
			cout << a[i];//存放从后向前存放,输出就要倒叙输出
		}
		cout << endl;
	}
	return 0;
}

3、 Hanoi双塔问题——2*(pow(2,n)-1)——暴力的话会爆内存

题目描述

给定 A,B,C 三根足够长的细柱,在 A 柱上放有 2n 个中间有空的圆盘,共有 n 个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为 n=3 的情形)。


现要将这些圆盘移到 C 柱上,在移动过程中可放在 B 柱上暂存。要求:

每次只能移动一个圆盘;
A、B、C 三根细柱上的圆盘都要保持上小下大的顺序;
任务:设 An 为 2n 个圆盘完成上述任务所需的最少移动次数,对于输入的 n,输出 An。

输入格式
输入文件为一个正整数 n,表示在 A 柱上放有 2n 个圆盘。

输出格式
输出文件仅一行,包含一个正整数,为完成上述任务所需的最少移动次数 An。

数据范围
1≤n≤200


输入样例:

2


输出样例:
 

6

 思路:双塔问题所求的结果是单塔问题的2倍,即res=2*(pow(2,n)-1)=pow(2,n+1)-2;

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 1e6 + 10;
int n, a[N], d, y = 2;

int main()
{
	while (cin >> n)
	{
		d = 1, a[0] = 1;
		for (int i = 1; i <= n + 1; i++)
		{
			int x = 0;
			for (int j = 0; j < d; j++)
			{
				int ans = a[j] * y + x;
				a[j] = ans % 10;
				x = ans / 10;
			}
			while (x != 0)
			{
				a[d++] = x % 10;
				x = x / 10;
			}
		}
		a[0] -= 2;//进行减2的操作(2的n次方尾数一定大于等于2)
		for (int i = d - 1; i >= 0; i--)
		{
			cout << a[i];
		}
		cout << endl;
	}
	return 0;
}

6、高精度除法

题目描述:

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

输入格式

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

输出格式

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

数据范围

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

输入样例:

7
2

输出样例:

3
1

1、高精度÷低精度

#include<iostream>
#include<algorithm>

using namespace std;
const int N = 1e6 + 10;

string s1;
int a[N], x, c[N];

int main()
{
	cin >> s1 >> x;//x为低精度
	int j = 1;
	for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';

	int ma = s1.size(), ans = 0;
	for (int i = ma; i >= 1; i--)//除法的核心运算
	{
		ans = ans * 10 + a[i];//上一位数*10加到下一位
		c[i] = ans / x;
		ans = ans % x;
	}

	while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
	for (int i = ma; i >= 1; i--)
	{
		cout << c[i];
	}
	cout << endl << ans;//余数的输出
	return 0;
}
  • 19
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大小胖虎

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

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

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

打赏作者

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

抵扣说明:

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

余额充值