基础编程题6-10 PTA阶乘升级版

题目要求实现1000以下的正整数的阶乘,由于int数据类型表示范围的限制,大数的阶乘已经无法用int类型正确表示,因此需要另外考虑一种思想,能正确计算大数的阶乘。

基本思想就是,用数组来表示一个大数,比如15! = 13 076 743 680 000, 可以表示成一个14位的int sum[13]数组。

下面看一个利用数组计算阶乘的简单例子,比如5! = 120:

假设已经计算到了4! = 24,

  1. 现在sum[0] = 4; sum[1] = 2; 
  2. 先让sum[0] * 5 = 20, 则sum[0] = 0, 产生一个进位2; 
  3. 那么sum[1] * 5 + 2 = 12,那么sum[1] = 2,产生一个进位1; 
  4. 然后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位)-2^{^{7}} ~ 2^{^{7}}-1-128 ~ 127
int整数型(默认有符号)4字节(32位)-2^{^{31}} ~ 2^{^{31}}-1-2147483648 ~ +2147483647
unsigned int 无符号整数型4字节(32位)0 ~ 2^{^{32}}-10 ~ 4294967295
long int 长整型8字节(64位)-2^{^{64}} ~ 2^{^{64}}-1 
long long int > 8字节(至少64位)  
short int 短整形2字节(16位)-2^{^{16}} ~ 2^{^{16}}-1-32768 ~ + 32767
float 浮点型4字节(32位)-2^{^{7}}*2^{^{23}} ~ 2^{^{7}}*2^{^{23}} 
double 双精度一般8字节(64位)-2^{^{31}}*2^{^{31}} ~ 2^{^{31}}*2^{^{31}} 
long double与double表示范围一致,只是精度更高  
    

其中,浮点型float在《计算机组成原理》这门课程里面会讲到,其表示方式是:第1位表示指数的正负,随后7位表示指数的值,后24位表示尾数(有效数)的正负和值。而双精度double其表示方式是:第1位表示指数的正负,随后31位表示指数的值,后32位表示尾数(有效数)的正负和值。因此,从这里也可以看出,双精度double型比浮点型float的精度更高,因为double有32位可以表示指数部分,这就意味着它能精确到2^{^{-31}},而float只能精确到2^{^{-7}}

需要指出的是,long double与long int不同,并没有扩大数的范围,而是提高了数的精度。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值