算法之高精度(三)

上篇我们讲完了输入和输出的内容:
高精度输入输出

从数学角度来说,不管是整数还是小数,不管表示的数字大还是数字小,都应该能够进行四则运算——加减乘除。这几乎是必须的。我们的高精度数字也应该能进行这样的处理。我们把涉及高精度四则运算的算法称之为高精度算法。不论如何,我们开始进行吧。不过,我想还是应该先介绍一下高精度算法包含哪些?
1.高精度加法——两个高精度数字相加
2.高精度减法——两个高精度数字相减(相减结果会大于0
3.高精度乘法——两个高精度数字相乘
4.高精度乘法——一个高精度数字乘以常规数字
5.高精度除法——两个高精度数字相除
6.高精度除法——高精度数字除以常规数字
这六种算法我们依次进行介绍。这一篇就来介绍高精度加法

我们以一个例子的方式来理解吧。计算684930287+501245612的和。
我想如果你看过前两篇关于高精度的内容,你就会了解到,这时,我们需要两个整数数组,分别存放这两个数字。

下标012345678
加数782039486
加数216542105

它们都是逆向存放的。主要原因是当产生进位时,可以在不移动数组元素的情况下实现
接下来便是加法了。我们回顾以下小学学习的加法法则。
从个位数字开始,两个对应数位上的数字相加。判断相加的结果是否有进位,如果有进位,则在更高一位的位置添加1
高精度数字的加法与小学学习的加法法则相同。
我们从下标为0的个位数字开始,7加上2的结果为9。不需要进位。下标为18加上1结果为9。仍然不需要进位。下标为22加上6结果为8,不需要进位。下标为30加上5结果为5,不需要进位。下标为43加上4结果为7,不需要进位。下标为59加上2结果为11,需要进位,因此,我们在下一位的位置放置一个进位数字。下标为64加上1结果为5,不需要进位。下标为78加上0结果为8,不需要进位。下标为86加上5结果为11,需要进位,因此,需要在下一位的位置放置一个进位数字。
这样,整个高精度数字的加法完整过程我们就描述清楚了。我们可以使用表格来表示整个过程。

下标0123456789
加数7820394860
加数2165421050
进位0000001001
结果9985711-105+1811-100+1

这个表格相较于上一个表格,我在右边添加了一列,原因是这个加法结果最高位需要进位,我们需要多提供一个数位。
结果栏也是显而易见,我使用运算的方式表达了进位的数字——原位上应减去10,高一位上应加上1。这里需要特殊说明一下,两个一位数字相加的结果不会超过20,因此,我们可以使用+1来表示进位。
我们尝试使用代码来解释这个过程。

//假设a1、a2表示两个高精度数字,其中
//a1 {7, 8, 2, 0, 3, 9, 4, 8, 6, 0}
//a2 {2, 1, 6, 5, 4, 2, 1, 0, 5, 0}
//假设两个高精度数字的数位个数不超过100

//我们使用函数表达高精度数字的加法
void add(int a1[], int a2[])
{
	int result[100] = {};	//使用一个数组来存放两个数相加的结果
	for(int i = 0; i < 100; ++i)
	{
		int num = result[i];	//先记录该位置上进位数字
		num += a1[i] + a2[i];	//进位加上两个数字之和
		if(num >= 10)	//达到10,就需要进位
		{
			num -= 10;	//移除进位的部分
			result[i + 1] = 1;	//下一位进位
		}
		result[i] = num;	//将结果存放在结果数组中
	}//经过循环,两个数的和便存放在result数组中
	
	//去前导0
	int k = 100 - 1;
	while(result[k] == 0 && k > 0)	//k > 0,确保一定有数字输出
		--k;
	for(int i = k; i >= 0; --i)
		cout << result[i]//倒过来输出,中间无需使用空格隔开
}

这样便详细了。但这个程序并不是十分满意。我们在函数内直接输出了结果,有时候我们并不想这样,我们希望在主函数中继续使用相加的结果。例如三个高精度数字相加时,两个数字相加的结果并不能直接输出,而是需要和第三个数相加——684930287+501245612+234871409.
主函数的代码可能是这样的:

int main()
{
	string nums[3] = {"684930287", "501245612", "234871409"};	//这个数组用来存放加数
	int result[100] = {};	//用来存放结果
	for(int i = 0;i < 3; ++i)
	{
		int a[100] = {};
		//将加数转换为整数数组,并且是逆向存放的
		string s = nums[i];
		for(int j = 0;j < s.size(); ++j)
			a[j] = s[s.size() - 1 - j] - '0';
			
		//高精度加法,相加的结果存放在result中
		add(result, a);	
	}
}

在这种情况,我们上述的代码就有些不太合适了。我们需要做一些改进。下面是改进的版本。

void add(int result[], int a[])
{
	for(int i = 0;i < 100; ++i)
	{
		result[i] += a[i];	//两个数字直接相加,结果存放在result中,存放在i的位置上
		//result[i]作为结果,有可能会达到进位的情况
		if(result[i] >= 10)
		{
			result[i] -= 10;	//直接使用结果减去10,保留个位数字
			result[i + 1] += 1;	//进位添加到高位,由于高位原位置存在数字,我们需在原位置上增加1
		}
	}//经过这层循环,结果都保存在result数组中了,这样主函数中就可以正常使用了。
	
	//由于不用输出,所以不需要除去前导0
}

这样的话,我相信关于高精度数字的加法描述的足够清晰了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值