大数运算——N阶乘(高精度)

上一篇我们已经系统的学习了高精度算法(http://t.csdnimg.cn/9cGaF) 但是光学习不实践必然是枯燥乏味的。现在我们来学习如何使用高精度。

大数运算——N阶乘

阶乘: 是基斯顿·卡曼(Christian Kramp,1760~1826)于 1808 年发明的运算符号,是数学术语。一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。1808年,基斯顿·卡曼引进这个表示法。
亦即n!=1×2×3×…×(n-1)×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。
平常遇到需要阶乘时我们大多数会用循环累乘或者函数的递归,但这种方法都是基于开一个变量,这个变量可以是int最大可以是long long但即使用long long变量范围也很有限(不到30!)。由此我们就思考有什么办法能算到更高位的阶乘呢?哎?
上一篇讲到的高精度乘法就能完美解决这个问题。
先用个具体阶乘举例:5!

让我们看代码吧~

#include<iostream>
#include<string.h>
using namespace std;
#define h 250000
char print[h] = { '1' };
int num1[h] = { 0 }, num2[h] = { 0 };
void fact(int n)
{
	int ans[h] = { 0 };
	int len1 = 0, sumlen,k = 0;
	len1 = strlen(print);
	//反转写入数组
	for (int i = len1 - 1; i >= 0; i--)num1[k++] = (print[i] - '0');
	k = 0;
	//将因数拆分反向装入数组
	while (n)
	{
		num2[k++] = n % 10;
		n /= 10;
	}
	//模拟乘法竖式
	for (int i = 0; i < len1; i++)
	{
		for (int j = 0; j < k; j++)
		{
			ans[j + i] += num1[i] * num2[j];
		}
	}
	sumlen = len1 + k;
	k = 0;
	//进位
	for (int i = 0; i < sumlen; i++)
	{
		if (ans[i] >= 10)
		{
			ans[i + 1] += ans[i] / 10;
			ans[i] = ans[i] % 10;
		}
	}
	//反转写入字符串
	while (!ans[sumlen])sumlen--;
	for (int i = sumlen; i >= 0; i--)print[k++] = ans[i] + '0';
}
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		fact(i);
	}
	cout << print;
}

核心思想: 将每次在主函数循环传入的数带入到函数中存到num2[],而num1[]是由每次循环得出结果的print[]传入,通过高精度乘法num1[]num2[]算出的结果先存入数组ans[],再由数组ans[]传入字符串print[],主函数通过循环反复调用函数fact()实现更新全局变量中的字符串print[](若为局部变量则会在每次函数结束直接删除)。

  • charprint[h]每次循环计算得出的积都会更新存放到该字符串中。intnum1[h]:用于存放每次print[h]保存的数作为新的因数。num2[h]:存放新的阶乘数作为另一个因数。
  • intlen1:计算num1[]字符串的长度。sumlen:用来计算两个因数的位数和(为什么算的是两个因数和呢?答:参考高精度乘法中maxlen)。k=0:数组起始下标。
  • num1[]反转写入数组:
    for (int i = len1 - 1; i >= 0; i--)num1[k++] = (print[i] - '0');在上一篇已经具体讲解过为什么要反转了(为了要逐位对齐),不同的是这次是直接反转写入数组中。
  • num2[]反转写入数组:
while (n)
	{
		num2[k++] = n % 10;
		n /= 10;
	}

一个整数的反转逐位写入数组的方法就是将自身摩除(%) 存入数组后再自身 整除(/) 循环当自身被整除为0时退出。
下面的算法都与高精度乘法相同就不多赘述了。
PS: 上述代码最多可算到5w的阶乘哦(最好不要轻易尝试它的极限,因为数字越大,算的越慢)

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
计算n的乘的精度算法有多种实现方式,以下是一种常见的方法: 1. 创建一个数组或字符串用于存储计算结果。数组的每个元素或字符串的每个字符代表计算结果的每一位数字。 2. 初始化结果为1。例如,可以将数组或字符串的第一个元素或字符设为1。 3. 从2开始遍历到n,进行乘法运算。 4. 将遍历的当前数字与已经计算出的结果进行乘法运算。这里需要注意,乘法运算涉及到进位问题,需要将进位值与结果的每一位相加。 5. 将结果存储到数组或字符串中的对应位置。 6. 遍历完成后,将数组或字符串中存储的结果转化为字符串形式或按需求输出。 以下是一个示例代码,实现了该精度计算乘的算法: ```python def factorial(n): result = [1] # 初始化结果为1 for i in range(2, n + 1): carry = 0 # 进位值初始化为0 for j in range(len(result)): temp = result[j] * i + carry # 乘法运算,并加上进位值 result[j] = temp % 10 # 取余数作为当前位的值 carry = temp // 10 # 取整数作为进位值 while carry > 0: # 处理最位以上的进位 result.append(carry % 10) carry = carry // 10 result.reverse() # 反转数组 return "".join(str(x) for x in result) # 将数组转化为字符串形式 n = int(input("请输入一个正整数n:")) result = factorial(n) print("n的乘为:", result) ``` 该算法的时间复杂度为O(n^2),空间复杂度为O(n)。通过这种精度算法可以计算出较大的乘结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值