题目要求实现1000以下的正整数的阶乘,由于int数据类型表示范围的限制,大数的阶乘已经无法用int类型正确表示,因此需要另外考虑一种思想,能正确计算大数的阶乘。
基本思想就是,用数组来表示一个大数,比如15! = 13 076 743 680 000, 可以表示成一个14位的int sum[13]数组。
下面看一个利用数组计算阶乘的简单例子,比如5! = 120:
假设已经计算到了4! = 24,
- 现在sum[0] = 4; sum[1] = 2;
- 先让sum[0] * 5 = 20, 则sum[0] = 0, 产生一个进位2;
- 那么sum[1] * 5 + 2 = 12,那么sum[1] = 2,产生一个进位1;
- 然后sum[3] = 1,最终结果为 120。
懂了这个基本思想,直接看代码就可以了。
#include <stdio.h>
void Print_Factorial ( const int N );
int main()
{
int N=1;
int i;
scanf("%d", &N);
Print_Factorial(N);
return 0;
}
void Print_Factorial(const int N) {
// 这里没什么好说的
if( N<0 || N>1000 )
printf("Invalid input");
// 这里也没有什么好说的
else if( N <= 12 ){
if(N==0 || N==1 )
printf("%d", 1);
else{
int i; int num = 1;
for(i=1;i<=N;i++)
num *= i;
printf("%d",num);
}
}else{
// 关键是这里,超过12的阶乘要用数组的思想处理
/*数组长度应该足够大,我试了sum[1000]会报段错误。4000没事。 */
int sum[4000];
sum[4000] = 0;
sum[0] = 1;
/*
i是阶乘元素,比如从1乘到12是用for(i)来完成;
j是sum数组的遍历元素;
m是sun数组有效部分的长度(无效部分被初始化为0,比如 4! = 24,则 m=2);
n是每一个sum[j]与阶乘元素乘法运算之后,产生的进位,比如sum[j]=3,i=8,那么sum[j]=4,进位n=2;
temp就是sum[j] * 阶乘元素i + 进位n 之后的数;
*/
int i,j,m,n,temp;
temp = 0; n = 0; m=1;
for(i=2;i<=N;i++){
for(j=0;j<m;j++){
temp = sum[j] * i + n;
sum[j] = temp % 10;
n = temp / 10;
}
/* 当sum[j]都遍历完之后,需要把产生的进位再加进来,并将sum[]的长度m++*/
while( n!= 0){
sum[m] = n % 10;
m++;
n /= 10;
}
}
/* 遍历输出*/
while(m > 0){
printf("%d",sum[m-1]);
m--;
}
}
}
附加:
为什么之前的阶乘代码不能用了,那是因为我们经常使用的int类型,其范围是-2147483648 ~ +2147483647。下面附上C语言常见的数据类型范围和位数。
名称 | 占位(二进制) | 范围 | 实际范围 |
char字符型 | 1字节(8位) | - | -128 ~ 127 |
int整数型(默认有符号) | 4字节(32位) | - | -2147483648 ~ +2147483647 |
unsigned int 无符号整数型 | 4字节(32位) | 0 ~ | 0 ~ 4294967295 |
long int 长整型 | 8字节(64位) | - | |
long long int | > 8字节(至少64位) | ||
short int 短整形 | 2字节(16位) | - | -32768 ~ + 32767 |
float 浮点型 | 4字节(32位) | - | |
double 双精度 | 一般8字节(64位) | - | |
long double | 与double表示范围一致,只是精度更高 | ||
其中,浮点型float在《计算机组成原理》这门课程里面会讲到,其表示方式是:第1位表示指数的正负,随后7位表示指数的值,后24位表示尾数(有效数)的正负和值。而双精度double其表示方式是:第1位表示指数的正负,随后31位表示指数的值,后32位表示尾数(有效数)的正负和值。因此,从这里也可以看出,双精度double型比浮点型float的精度更高,因为double有32位可以表示指数部分,这就意味着它能精确到,而float只能精确到
。
需要指出的是,long double与long int不同,并没有扩大数的范围,而是提高了数的精度。