n的阶乘(防止栈溢出)

首先用我们最收悉的递归方法来完成:

int Fun1(int n)
{
    
    
	if(n<=1)
		return 1;
	else
		return Fun1(n-1 )* n;
}

还有循环方法:

int Fun2(int n)
{
    
    
	int sum=1;
	for(int i;i<=n;++i)
	{
    
    
		sum=sum * i;
	}
	return sum;
}

但是,我们遇到13的阶乘怎么办?13!超出int型变量的范围,得不到正确的结果。为了计算更大数的阶乘可以将int型改为unsigned long型。

unsigned long Fun3(unsigned long n)
{
    
    
	if(n<=1)
		return 1;
	else
		return (unsigned long)n * Fun3(n-1);
}

不过在计算20以后的阶乘也将会溢出,这时我们就要考虑栈溢出的问题了。

考虑将多位数相乘化解为一位数相乘。
如11!=39916800,若需求12的阶乘,则需要将39916800与12相乘,可利用乘法分配率。
在这里插入图片描述
可以使用一个数组来保存阶乘每一位的结果,一个数组元素保存一位数。
在这里插入图片描述通过进位操作使得数组中每个元素保存的值都只有一位数。这样可以保存任意多位的阶乘结果,不再受变量的取值范围的限制。

代码如下:

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<stdlib.h>

#define true	1
#define false	0
 
void calculat(int *fact, int n)
{
    
    
	int i;
	int num=fact[0];
	int carry=0;
 
	for(i=1; i<=num; i++)
	{
    
    
		fact[i] = fact[i]*n+carry;
		if(carry = fact[i]/10)
		{
    
    
			fact[i] = fact[i]%10;
		}
	}
	
	while(carry)
	{
    
    
		fact[i++] = carry%10;
		carry = carry/10;
	}
	fact[0] = i-1;
}
 
int Fun4(int n, int **result)
{
    
    
	double sum=1;
	int digit;
	int i;
	int	*fact;
 
	if(n<=0 || result==NULL)
	{
    
    
		return false;
	}
	for(i=1; i<=n; i++)
	{
    
    
		sum += log10(n);
	}
	
	digit = (int)sum;
	fact = (int *)malloc((digit+1)*sizeof(int));
	if(fact == NULL)
	{
    
    
		return false;
	}
	fact[0]=1;
	fact[1]=1;
	for(i=2; i< digit+1; i++)
	{
    
    
		fact[i]=0;
	}
 
	for(i=1; i<=n; i++)
	{
    
    
		calculat(fact, i);
	}
	
	*result = fact;
	return true;
}
 
void printnum(int *result)
{
    
    
	int num;
	
	if(result == NULL)
		return;
	num = result[0];
	while(num)
	{
    
    
		printf("%d",result[num]);
		num--;
	}
	printf("\n");
}
 
int main()
{
    
    
	int n;
	int *result;
 
	while(EOF != scanf("%d", &n))
	{
    
    
		if(false == Fun4(n, &result))
			return false;
		printnum(result);
		free(result);
	}
	return true;
}

另外,在提供一种类的方法:用数组的方式来存储每一位数据
举个例子:假如我们得到了4!= 24,在数组中是以倒序的方式存储,即42,a[1]= 4,a[2] = 2(数组下标从1开始)
现在要计算5!内层for循环对4和2进行处理,即每一位都乘以5。首先a[1] = a[1]*5 + 0(h)= 20,h从0变为2,a[1] = 0;然后a[2] = a[2] * 5 + 2 = 12,h从2变为1,a[2] = 2;这时内层for循环执行结束。
内层for循环的作用是更新已经存在的位数中的每一位与i的乘积的结果。
接着执行while循环,目前h = 1,a[3] = 1,h 从1变为0,然后退出while循环。处理结束就得到了5! = 120。p的位数增加到3位。
while循环的作用是计算p更新之前的位数之后的进位
比如说p = 2的时候,数组中为42,然后内层for循环把42更新为02,while循环增加进位1,整个数组变为021。
代码如下:

#define MAX 40000  
int main()  
{
    
      
    int n;  
    while(scanf("%d",&n)!=EOF&&n>=0)  
    {
    
      
        int i,j;  
        int a[MAX];      //存数运算结果  
        int p,h;           //p存储当前结果的位数,h为进位  
        a[1]=1;  
        p=1;  
        for(i=2;i<=n;i++)   //循环与2,3,4.....n相乘  
        {
    
      
            for(j=1,h=0;j<=p;j++)    //让a[]的每位与i相乘  
            {
    
      
                a[j] = a[j] * i + h ;  
                h = a[j] / 10 ;  
                a[j] = a[j] % 10 ;  
            }  
            while(h>0)         //如果h不为0  
            {
    
      
                a[j] = h % 10 ;  
                h = h / 10 ;  
                j++;  
            }  
            p = j - 1 ;            //将当前的位数赋给p  
        }  
        for(i=p;i>=2;i--)  
        {
    
      
            printf("%d",a[i]);  
        }  
        printf("%d\n",a[i]);  
    }  
    return 0;  
}  

猜你喜欢

转载自blog.csdn.net/Chenjiahui_LYee/article/details/102989806