大数阶乘(C++实现)

C/C++语言中,int范围为[-231, 231-1] 即 [-2147483648, 2147483647]。
在进行阶乘运算中,12!!!=479001600,13!!!=6227020800,也就意味着超过13的阶乘就不能用int型进行存储。对于大数的阶乘,要换一种方式进行存储。
输入一个数值n,首先要估算n!的位数:

int getSize(int n)  //计算结果的大概位数
{
	int i, j, num;
	for(i = 1, j = n; j / 10 > 0 || j % 10 > 0; ++i)
	{
		j /= 10;
	}
	//num=n*--i+1;  //此计算式为多次总结归纳得到
	num = n*--i / 3 + 1;  //一个int存储的数字的范围为0~9999,按理说是n*--i/4+1,此处多申请一些以防开辟的空间不足
	return num;
}

通过此函数得到的位数会比实际的位数要多。
得到位数size之后,申请一个长度为size的int型数组,初始化末位为1,其余全为0;
然后从末位起倒着乘以每一个数,将数组中每一个数字的范围为0~9999,超过范围的数字向前进位。最后将结果通过string字符串返回。代码如下:

string factorial(int n)
{
	string outp;
	int *temparr, num;
	int getSize(int n);
	int getNumLength(int n);

	int i, j, k;
	int wsize = 10000;
	int size = getNumLength(wsize) - 1;

	num = getSize(n);
	temparr = new int [num];

	for(i = 0; i < num; ++i)
	{
		if(i == num - 1) temparr[i] = 1;
		else temparr[i] = 0;
	}
	if(n == 0) temparr[num - 1] = 1;
	else
	{
		for(i = 1; i <= n; ++i)
		{
			int count = num - getSize(i) - 1;
			for(j = num - 1; j >= count && j - 1 >= count; --j)
				temparr[j] *= i;
			for(k = num - 1; k >= count && k - 1 >= count; --k)
			{
				if(temparr[k] > wsize) 
				{
					temparr[k - 1] += (temparr[k] / wsize);
					temparr[k] = (temparr[k] % wsize);
				}
				else continue;
			}
		}
	}
	int midd = 0;
	for(i = 0; i < num; ++i)
	{
		if(temparr[i] == 0) midd += 1;
		else break;
	}
	
	char s[8];
	sprintf(s, "%d", temparr[midd]);	 //从第midd位开始为非0数
	outp += s;
	for(i = midd + 1; i < num; ++i)
	{
		sprintf(s, "%04d", temparr[i]);	//四位有效数字,不足的情况用0填充
		outp += s;
	}

	if(temparr)
	{
		delete [] temparr;
		temparr=NULL;
	}

	return outp;
}

其中,int getNumLength(int n)函数的实现代码为:

int getNumLength(int n)
{
	if(n == 0) return 1;
	else if(n < 0) return -1;

	int size = 0;
	while(n)
	{
		n /= 10;
		++size;
	}
	return size;
}

main函数中:

int main(int argc, char* argv[])
{
	int getSize(int n);
	int getNumLength(int n);
	string factorial(int n);

	cout << "//------------------------------大数阶乘------------------------------//" << endl;
	cout << "//--------- 数组求阶乘,为方便运算,原则不大于100000,否则会很慢 --------//" << endl;

	int n;
	cin >> n;
	string s;

	double timebegin = (double)clock() / CLOCKS_PER_SEC;

	if(n < 0) 
	{
		cout << "输入有误!!!" << endl;
		return 0;
	}
	else
	{
		s = factorial(n);
		cout << n << "!=";
		cout << s << endl;
		if(n >= 30)	//启用科学计数法
		{
			cout << n << "!=" << s[0] << ".";
			for(int i = 1; i < 20; ++i)
				cout << s[i];
			cout << "e+" << s.size() - 1 << endl;
		}
	}

	printf("time: %.6f\n\n", (double)clock() / CLOCKS_PER_SEC - timebegin);
	system("pause");
	return 0;
}

运行结果:

输入结果
20!20!20!这里写图片描述
1000!1000!1000!这里写图片描述
20000!20000!20000!这里写图片描述

欢迎大家批评指正。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

A-Chin

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

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

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

打赏作者

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

抵扣说明:

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

余额充值