求阶乘(考虑溢出)

来源:互联网 发布:vue仿豆瓣app源码下载 编辑:程序博客网 时间:2024/04/30 13:58

求阶乘


本文前半部分引用于“月心小筑”的百度空间,原理讲得简单易懂,我也非常感谢该博文,后面我会贴出我的代码,欢迎网友指点。


最熟知的便是利用递归来求阶乘了:

#include <stdio.h>int factorial(int n){    if(n<0)        return 1;    if(1==n)        return 1;    else        return n*factorial(n-1);}


可在计算13!=6227020800时便超出int型变量的范围,得不到正确的结果。

        为了计算更大数的阶乘可以将int型改为unsigned long型:

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


不过在计算20以后的阶乘也将会溢出。

        可考虑将多位数相乘化解为一位数相乘,如11!=39916800,若需求12的阶乘,则需要将39916800与12相乘,可利用乘法分配率。如下图:


可以使用一个数组来保存阶乘每一位的结果,一个数组元素保存一位数。如下图:


通过进位操作使得数组中每个元素保存的值都只有一位数。这样可以保存任意多位的阶乘结果,不再受变量的取值范围的限制,只受操作系统寻址能力和计算机内存的限制了。


代码:

#include <stdio.h>#include <math.h>#include <stdlib.h>#define true1#define false0void 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 factorial(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 == factorial(n, &result))return false;printnum(result);free(result);}return true;}