原题目:
本题要求实现一个打印非负整数阶乘的函数。
函数接口定义:
void Print_Factorial ( const int N );
其中N
是用户传入的参数,其值不超过1000。如果N
是非负整数,则该函数必须在一行中打印出N
!的值,否则打印“Invalid input”。
裁判测试程序样例:
#include <stdio.h>
void Print_Factorial ( const int N );
int main()
{
int N;
scanf("%d", &N);
Print_Factorial(N);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
15
输出样例:
1307674368000
分析:
题目的意思是根据输入的整数计算该整数的阶乘,本题的难点在于如何计算大数乘法。
只要将大数乘法实现,每次循环计算1到N的结果就是本题的答案。
大数乘法的计算:
由于数据大小的限制,使用Int、Long等数据类型无法存储1000阶乘的值,故需要使用数组来进行简化计算,整数数组保存大数的每一位,索引为0存储整数个位,依次存储整数每个位上的数字,两个数组计算每一位的乘积先保存在C数组中,此时C数组中保存的是每一位乘积和,并不是乘积运算后的结果,故需要对每一次的乘积结果数组计算模除与整除计算出每一位的值,依次循环计算最后的值即是结果。
代码:
C版本
void Print_Factorial ( const int N ){
//定义乘积数组A,保存每一次的结果
//定义乘积数组B,用于保存新计算的值,
//定义临时结果数组,存储每一次A*B的值
int A[5000] = {0}, B[5000] = {0}, C[5000] = {0};
//定义数组A和数组B的索引:a_index,b_index
//定义cur乘积的进位,定义k临时结果数组长度
int a_index = 1, b_index = 0, cur = 0, k = 0;
//A数组初始化数值为1,未使用值为-1,B数组初始化为-1,C数组初始化为0
for(int i = 0 ; i <= 4999; i++){
if(i!=0){
A[i] = -1;
}else{
A[i] = 1;
}
B[i] = -1;
C[i] = 0;
}
//不合法值直接打印错误
if(N < 0){
printf("Invalid input\n");
}else{
//合法值从2开始计算到N的阶乘
for(int index = 2; index <= N; index++){
//将第index次乘积的原始值存储到B数组中,后面按位与A数组相乘
for(int m = index; m != 0; m=m/10){
B[b_index++] = m % 10;
}
//按位将A和B数组相乘,注意多位乘法时数值相加的索引位置
for(int i = 0; i < b_index; i++){
k = i;
for(int j = 0; j < a_index; j++){
C[k++] += (B[i] * A[j]);
}
}
//临时结果数组C需要从新计算
for(int i = 0; i < k; i++){
cur = C[i] / 10;
C[i] = C[i] % 10;
if(cur != 0){
C[i+1] = C[i+1] + cur;
}
}
//更新临时数组C的长度,从数组索引最大值开始依次减少防止中间出现0而计算错误
for(int i = 4999; i > -1; i--){
if(C[i]!=0){
k = i+1;
break;
}
}
//初始化A和B数组以及索引
a_index = 0;
b_index = 0;
for(int i = 0; i < 4999; i++){
A[i] = -1;
B[i] = -1;
}
//临时结果数组C从新保存到数组A中,方便后面计算
for(int i = 0; i < k; i++){
A[i] = C[i];
a_index++;
}
//临时结果数组初始化
for(int i = 0; i < 4999; i++){
C[i] = 0;
}
}
//从非-1值开始打印结果,因为数组存储整数是高索引存储高位数,低索引存储低位数
for(int i = 4999; i>-1; i--){
if(A[i] != -1){
printf("%d",A[i]);
}
}
}
}