高精度阶乘之和

7 篇文章 1 订阅
1 篇文章 0 订阅

题目描述:

用高精度计算出S=1!+2!+3!+…+N!(N≤50),其中"!"表示阶乘,例如:5!=5*4*3*2*1。

输入正整数N,输出计算结果S。

输入格式

一个正整数 n。

输出格式

一个正整数 S,表示计算结果。

解题思路:

-----由于阶乘的增长速度特别快,计算结果S的最大值可以达到70多位数,远超我们计算机能够表达的范围,所以我们不能用常规的变量记录阶乘以及阶乘和的结果。那我们要用什么方式记录计算结果呢?

-----我们设置两个大小为MAX_SIZE的整形数组factres分别记录阶乘以及阶乘和的结果,数组中的每一个元素就代表了一位数(0~9),只要调整MAX_SIZE的大小,就可以解决MAX_SIZE以内精度的计算。计算过程怎么实现呢?

-----由于在相乘或相加的运算过程中会发生溢出(产生进位),超过了一个数组元素能表示的范围,这时我们用整型变量c来表示进位,当运算过程产生了进位,我们就用c记录这个进位的结果,运用到下一位数运算的过程。

这里的进位c可以是多位数,我们以较为复杂的乘法作为例子:

456 x 7:

第一次运算:个位数6和7相乘,得到42,即进位为4,个位数运算后结果为2

第二次运算:十位数5和7相乘,结果39(乘法结果35加前一位数进位4),得到进位3和十位数结果9

第三次运算:百位数4和7相乘,得到结果31,进位为3,百位数结果为1

第四次运算:运算已经结束了,只需要把前一位结果放到千位数就行,如果是两位数进位,则分别放到万位和千位。

 

 补充一点:我们用len1,len2分别表示fact,res的位数大小,因为计算之前我们并不知道计算结果会有多少位数,所以MAX_SIZE可能会设置非常大 ,这会让很多计算结果产生特别多的无效位(前导0),所以记录数组有效位长度是非常有必要的。

而len1和len2的更新方式为:(计算后的长度)=(计算前的长度)+(最后一位进位的位数)

大家可以跳回第三步运算自行理解。

加法的运算过程和乘法类似,较为简单就不演示了。

#include<iostream>
using namespace std;

const int MAX_SIZE = 1000;  //数字位数

//相乘函数
int multi(int* fact, int i, int len)
{
	int c = 0;  //进位
	//如果没定义len,则for的判断语句(k < MAX_SIZE)
	for (int k = 0; k < len; k++)   
	{
		int mul = fact[k] * i + c;  //位数相乘结果,并加上前一位数的进位
		fact[k] = mul % 10;  //更新当前位数
		c = mul / 10;        //更新进位
	}
	//最后一位相乘的结果可能有进位,我们要把进位更新到fact中,并且更新长度
	while (c)
	{
		fact[len++] = c % 10;
		c /= 10;
	}
	return len; 
	//如果函数参数len是用引用传递的话,这里不用返回也可以更新len的值
	//详见(函数参数传递,值传递、引用传递和地址传递的区别)
}
//加法函数
int add(int* fact, int* res, int len)
{
	//len表示 fact 和 res,两个数组中的位数较大值 
	int c = 0;  //进位
	
	for (int k = 0; k < len; k++)
	{
		int sum = fact[k] + res[k] + c;  //位数相加,并加上前一位数的进位
		res[k] = sum % 10;  //更新当前位数
		c = sum / 10;        //更新进位
	}
	//最后一位相加的结果可能有进位,我们要把进位更新到res中,并且更新长度
	while (c)
	{
		res[len++] = c % 10;
		c /= 10;
	}
	return len;
}

int main()
{
	int n;  cin >> n;
	//定义两个数组,分别表示阶乘,阶乘和
	int fact[MAX_SIZE], res[MAX_SIZE];  
	//初始化两个数组
	for (int i = 0; i < MAX_SIZE; i++)
	{
		fact[i] = 0;
		res[i] = 0;
	}

	fact[0] = 1;

	int fact_len = 1, res_len = 0;  //两个数组的位数
	
	for (int i = 1; i <= n; i++)
	{
		fact_len = multi(fact, i, fact_len);//计算i的阶乘,并返回阶乘结果fact长度
		res_len = add(fact, res, fact_len); //计算i的阶乘和,并返回相加结果res长度

		//add的函数第三个参数表示有效位数,所以传入两个数组长度的较大值
		// fact_len的有效位一般比res_len大,所以传入fact_len
		//如果不知道fact_len和res_len那个大,可以用下面代码解决
		/*
		int temp_len = max(fact_len, res_len);
		res_len = add(fact, res, temp_len);
		*/
	}
	//输出(从高位开始输出)
	for (int i = res_len - 1; i >= 0; i--)
	{
		cout << res[i];
	}
	cout << endl;
}

如果觉得本文有帮助到您,请点击下方一键三连,助力一下博主!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值