题目描述
算法思路描述
我觉得这题相较于大整数乘法来说在代码的处理上面比较的好处理,当我们求一个数的阶层,比如说求20的阶层,我们的想法就是从1一直遍历到20然后进行累乘,但是它与普通的求阶层的算法不一样的地方就在于20的阶层已经远远的超过了计算机所能存储的最大的整数,因此对于结果的存储我们只能借助整型数组来存放,还有一个就是当计算20的阶层的时候,19的阶层我们肯定是已经求解出来了的,那么求20的阶层就是用19的阶层去乘以20,所以我们总是在用一个小数去乘以一个计算机不能表示的大数,这里模拟一下求20的阶层的一个中间状态,即当10的阶层已经求出来并且放在了结果数组中,求11的阶层,那么只需要将10的阶层乘以11即可,那么我们的思想是用结果数组中的每一位去乘以11,然后在错位相加在此过程中更新结果数组、如图:
那么我们只需要一层for循环就可以模拟上述过程,从上图的计算过程中我们注意到,每进行一次循环我们都可以更新原来的结果数组中的一个数,这么说你可能不太理解,举一个例子,比如说在第一次循环的时候,此时循环控制变量i=0,此时我们将结果数组中下标为0的位置处的数字去乘以11得到的结果是00,这时候其实结果数组中下标为0的位置处的数字就可以更新为0了,这个数字是0对10取模运算的结果,因为00的右边的一个0在后序的操作中没有数再和它进行相加了,然后00的第一个0需要累积到下一次循环和下一次循环所得到的数进行相加。同样的当进行第二次循环时,此时的循环控制变量的值变为了1,此时我们需要用结果数组中的下标为1的数字去乘以11然后和上一次循环中留下来的数字即没有被保存到结果数组中的部分进行相加,得到结果88,那么就更新结果数组中下标为1处元素的值为88%10,然后没有被添加到结果数组中的部分是88/10,这个部分需要留到下一次和下一次的运算结果进行相加。那么理解此题的思路之后代码就可以写出来了;
代码实现如下:
//高精度阶乘
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define N 3000
int result[N] = { 0 }; //用于存放高精度乘数
int main()
{
int n;
while (scanf("%d", &n) != EOF)
{
int digit = 1; //用于记录结果数组中当前有效的位数
//从1开始乘一直乘到n,所以先将结果数组中存放的数改成1,此时需要1进行乘法运算的次数为1,因为结果数组中的有效位数只有一位
result[0] = 1;
int temp; //用于存放结果数组中的每一位与当前数的乘积
int no_add = 0; //用于记录还未进行相加的数
for (int i = 2; i <= n; i++)
{
for (int j = 0; j < digit; j++)
{
temp = result[j] * i + no_add;
result[j] = temp % 10;
no_add = temp / 10;
}
while (no_add)
{
result[digit] = no_add % 10;
no_add = no_add / 10;
digit++;
}
}
for (int j = digit - 1; j >= 0; j--)
{
printf("%d", result[j]);
}
printf("\n");
}
}
运行结果截图
祝学习进步,生活愉快!