第一次写,为了记录一些题目的解题思路,方便日后反思以及优化。
还是小白,没学过很多算法,还不会用更高级的函数,如果有纰漏和建议欢迎指正和提出!~(●'◡'●)
准确计算自然数N的阶乘(N≤50)
题目描述
对于自然数N的阶乘,当N比较小时,可以32位整数int范围内准确表示
例如12!=479001600<2147483647(231-1)
而20!=2432902008176640000<9223372036854775807(263-1)可以在64位整数long long int范围内准确表示
但是N取值更大时,N!只能使用浮点数计算,从而产生误差
要求:输入自然数N(N≤50),准确计算自然数N的阶乘
说明50!≈3.04e+64,可以考虑定义数组存储计算结果的各位数字
输入
测试数据有多组,处理到输入结束
输出
每个输出占1行
输入样例
1
10
20
29
30
输出样例
1
3628800
2432902008176640000
8841761993739701954543616000000
265252859812191058636308480000000
AC代码
#include<stdio.h>
int main()
{
//n为被阶乘的数,x为需要进位的数,y为计算过后的个位数
int n, x, y, num = 0;
//a数组逆序储存计算后的各位数结果
int a[100000] = { 0 };
while (scanf("%d", &n) != EOF)
{
//此处重置所有参数,开始下一次计算
num = 0;
for (int i = 0; i < 100000; i++)a[i] = 0;
int k = n;
//这里将第一个数的各位数逆序存入数组中
//例:n=37,a[0]=7,a[1]=7
while (k != 0)
{
a[num++] = k % 10;
k /= 10;
}
//开始计算,直到n=1说明所有阶乘都完成
while (n != 1)
{
//初始化各参数
n--;
x = 0, y = 0;
//这边的计算思路是各位数分别乘以n,然后大于个位的数加到后一位的数中
//即:194*20 = 100*20 + 90*20 + 4*20
//num表示计算后的数字位数
for (int i = 0; i < num; i++)
{
y = a[i] * n;
a[i] = y + x;
x = a[i] / 10; //取需要进位的数
a[i] %= 10;
if (x !=0&&i==num-1)num++; //如果还有需要进位的且现在已经是最后一位则位数+1
}
}
//逆序输出
for (int i = num - 1; i >= 0; i--)
{
printf("%d", a[i]);
}
putchar('\n');
}
}
总结
- 这种要求精确计算的大数字一般的处理方法就是用数组来分位计算啦
- 对于需要输出的位数可能可以通过更好的方法来得出,但是做完之后实在没精力再去优化了,姑且先这样
- 重置数组a这一步好像很浪费时间的样子,似乎可以优化一下让没用到的位数不被重置下去
- 分位计算那一块(倒数第二个for)的顺序理了好久,需要先乘以原数字,然后再加上前一位需要进位的数,最后再取需要进位的数
- 有一次提交的时候运行错误,估计是分配的内存太小了,所以就把a数组又扩大到了十万位
嘛,以为要做很久的,没想到用的时间比预期的少,也没又出现超时的情况,但是代码好冗长,而且许多地方可以优化,之后要理一下数据存储空间的关系,就先这样吧!——2021.4.29