处理大整数------计算n!(阶层)

我们知道,计算n!的方法通常有两种,一种是利用循环进行迭代,而另外一种就是利用函数进行递归运算,在一般情况是是可行的,但是当n比较大的时候,就不能通过这样直接迭代了,因为在我们使用的计算机语言中,对整数类型,一般为 int、long。稍微大点的就是 long long 了,尽管使用语言提供的最大整形,也不能直接处理n比较大的情况,如:n为100时,更何况是1000、或则更大。

利用循环直接进行迭代为例,代码如下:

#include<iostream> 

using namespace std;

int main()
{
	unsigned long long n;
	cin>>n;//输入n
	unsigned long long i,sum = 1;
	if(n == 0) 
		return 0;
	else if(n == 1)
		return 1;
	else
	{
		for(i=2;i<=n;i++)	
			sum *= i;
	}
	cout<<sum<<endl;//输出结果 
	
	return 0;
}

运行程序,对不同的输入,结果如下:

可见当输入的数据大于65时,其输出结果为0,其实输入66时,输出的结果就为0了

通过后面的计算可以发现,这里对输入65时,其输出的结果是错误的,

正确的结果应该为:8320987112741390144276341183223364380754172606361245952449277696409600000000000000

我们可以大概估算一下位数就知道了,对65,假设全是55个10相乘(舍去0-9),那么得到的结果的位数应该是56位的,而不是上面结果中的短短几位

同样,使用相同的数据类型,利用函数递归也能得出相同的结果。


看了别人的方法,基本都是用数组实现的,对位数也不好控制,当位数大了数组就会发生越界,在这里,我用的是向量,所以就不用考虑越界问题,直接输入数据求解。
其算法思想,模拟手算:

1、用当前数据乘以向量中的每一个数,结果返回到原来向量相应的单元

2、然后依次处理向量单元的每一个数据,分别除以10,将商加到前面一个单元,

      如果前面没有单元,就插入到前面(当然插入后还要处理);将余数放回原来

      单元。最后,如果是有发生插入,即向量的第一个元素(在向量下标为0处)除

      以10的商不为0,也即该元素大于10,对插入的单元里的元素做以下处理:

将该元素除以10,原来单元放余数,如果商不为0,将其插入到前面

一个单元。重复执行该步骤,直到商为0为止。

——————————————————————————————————————————————

基于该思想,求n!的代码如下:

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

int main()
{
	int n;
	int i,j,k=0;
	vector<int> vec;
	vec.push_back(1); 
	cin>>n;
	if(n == 0)
		cout<<0<<endl;
	else if(n == 1)
		cout<<1<<endl;
	else  //n大于1的情况
	{
		for(i=1;i<=n;i++)
		{
			for(j=vec.size()-1;j>=0;j--)//每个单元的元素都乘上
			{
				vec[j] *= i;
			}
			k = 0;//是否有进位,初始为0
			for(j=vec.size()-1;j>=0;j--)
			{
				vec[j] += k;//加上进位的数 
				k = vec[j]/10;
				vec[j] = vec[j]%10;
			}
			while(k)//不能将k直接插入到前面,因为k有可能大于10 
			{
				vec.insert(vec.begin(),k%10);//直接放余数到前面即可 
				k = k/10;
			}
		}
	}
	for(i=0;i<vec.size();i++) 
	{
		cout<<vec[i]; //输出每位数,倒数第二位为十位
					  // 最后一位为个位 
	}
	cout<<endl;
	return 0;
}

最后值得思考的是:

1、上面初始向量的数据类型为整形,而每个单元存放数据却是0--9,这样是不是一种浪费呢?

答案是否定的,如果当处理大数的阶层时,越到后面,向量的每个单元乘上一个大数,结果就

有可能大于该数据类型所表示的范围,导致结果错误。更何况,如果进位连续发生,致使数据

单元的内容也变得更大,再乘上一个数,结果当然也是错误的!


2、另外,如果不考虑上面的情况,那么的确是一种浪费,这也使得当初我想对算法进行改进:

方案1:定义向量时,声明数据类型的范围小点(显然这是行不通的)

方案2:如果每个单元存放一位数,的确显得有点浪费,可以存放2位、3位..........或则更多位数,

这样可以吗?这样也是不行的。解释如下:

存放2位数据时,假设运算过程中,某一单元的数据为101,那么101除以100的余

数为1,而不是01,这样继续下去的话,该单元存放的就是1,而不是01,显然这使

得最终结果的位数减少了,从而导致错误,如果采用某种办法来处理的话,应该是可

行的,但是如果每个数据单元存放的位数更大时,可想,处理的办法应该更为复杂!

所以:

不要在定义向量时,时向量的数据类型太小,而应该根据需要而方法才行!

最好让每个单元存放的数据位数为1,除非你愿意去处理那些比较麻烦的情况!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值