高精度计算阶乘递加

本人也是第一次在csdn上面写博客,如果有什么解释不清和逻辑上的错误,还请大家能够海涵并能不灵赐教。

这道题来自于洛谷的第三个提单,用来实现从一的阶乘加到n的阶乘的和。通常情况下,我们会直接通过for循环来遍历每一个阶乘并相加,比如说下面这样:

#include<stdio.h>
int main()
{
	int n,i,j;
	unsigned long long sum=0,num=1;
	scanf ("%d",&n);
	for (i=1;i<=n;i++)
	{
		for (j=1;j<=i;j++)
		{
			num=num*j;
		}
		sum=sum+num;
		num=1;
	}
	printf ("%lld",sum);
}

这样看上去简洁明了,很好理解,但存在一个很大的问题,那就是如果给出的数字太大,则会出现数据溢出。这道题用到了无符号长长整型,无符号长长整形占据八个字节,其大小约为2的64次方,范围为0到1844 6744 07337 0955 1615之间,为c语言能储存的最大数字。但是当给n赋值为50的时候,真实的结果应该是31035053229546199656252032972759319953190362094566672920420940313

本以为unsigned long long int已经很大了,但是和上面这个数字比起来,简直不值一提。全宇宙的原子个数约为10的80次方。面对如此庞大的数字,我们已经不能使用变量来存储,只能通过数组来处理。但应该如何处理和实现这个代码呢,我们先看下面这个例子;

33333333
*2
66666666

通过这样,我们用一个数组的每一位来和要成的数字进行乘法运算,就可以得到结果,其思想和小学乘法的思想一致。

但是出现了第一个问题,如果某一个的数字超过了十,那么该如何处理呢,思路如下:

12323129
*3
369693627=20+7
3696936+27

就像这样,将个位的数字取十的模,再将其除以十,将十位以上的数字加到前一位上,这样就可以将每一位数字都化为一位数字。(在这里要提前说明要考虑数组长度不够的情况)

之后的第二个问题,数组中的数字是从前往后排列的,但是加,减,乘都是从各位开始的,如果两个数字长度不齐,就会在计算中出现麻烦。为了解决这个问题,我们不妨逆天道而行,数学中从前往后进位,我们可以从后往前进位。

第三个问题,构建好数组后该如何输出呢,这个问题其实不难解决,我们的数字是逆向储存的,我们也需要找到起始位点,最后从后往前输出,即找到从后往前的数字中,不为零的那个数。

综上,我们就有了个大概得框架,这样就有了实现代码的理论基础。

代码如下:

#include<stdio.h>
int main()
{
	int i,num[151]={0},arr[151]={0},n,j;//num用来计算所有阶乘的和,arr用来计算所需的阶乘结果,数组后的数字应根据实际情况调整大小
	scanf("%d", &n);
	num[0]=arr[0]=1;
	for (i=2;i<=n;i++){
		for (j=0;j<150;j++)//这里运算的结果不能超过100位,如果超出,就需要扩大该值(运算结果的大概位数)
			arr[j]*=i;//构建阶乘
		for (j=0;j<150;j++)
			if (arr[j]>9){
				arr[j+1] += arr[j]/10;//倒序进位
				arr[j]%=10;
			}
		for (j=0;j<150;j++){
			num[j]+=arr[j];//计算结果
			if (num[j]>9) {
				num[j+1] += num[j]/10;//倒序进位
				num[j]%=10;
			}
		}
	}
	for (i=150;i>=0;i--){
		if (num[i]!=0) break;//找到起始位
	}
	for (j=i;j>=0;j--) printf("%d", num[j]);//倒序输出
	return 0;
}

具体的细节已经在上面的代码中注释。

感谢大家能够耐心听我的讲解。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值