大数,高精度计算---大数阶乘

大数是算法语言中的数据类型无法表示的数,其位数超过最大数据类型所能表示的范围,所以,在处理大数问题时首先要考虑的是怎样存储大数,然后是在这种存储方式下其处理的实现方法。

一般情况下大数的存储是采用字符数组来存储,即将大数当作一个字符串来存储,而对其处理是按其处理规则在数组中模拟实现。

六  大数阶乘。

 

阶乘问题比较典型,下面,将通过自己的学习逐步介绍。

首先介绍两种常规方法。

 

1.迭代法

[cpp]  view plain copy
  1.  /* 利用 迭代 来计算整数n的阶乘 */   
  2. #include <stdio.h>  
  3. int main()  
  4. {  
  5.     int n;  
  6.     long result = 1;  
  7.     scanf("%d",&n);  
  8.     while( n>1 )  
  9.     {  
  10.         result *=n;  
  11.         n--;  
  12.     }  
  13.     printf("%ld",result);  
  14.     return 0;  
  15. }  

 

2.递归法

[cpp]  view plain copy
  1. /* 利用 递归 来计算整数n的阶乘 */  
  2. #include <stdio.h>  
  3. long factorial_recursion( int n )  
  4. {  
  5.     if( n<=0 )  
  6.     {  
  7.         return 1;  
  8.     }  
  9.     else  
  10.     {  
  11.         return n * factorial_recursion( n-1 );  
  12.     }  
  13. }  
  14. int main()  
  15. {  
  16.     int n;  
  17.     long result;  
  18.     scanf("%d",&n);  
  19.     result = factorial_recursion( n );  
  20.     printf("%ld",result);  
  21.     return 0;  
  22. }  



这两种方法都比较常规,也比较简单,初学c的时候,还没接触算法,就是利用这样的思路完成。

但是,一旦求N!中N的值大了,那么不管是int 还是 long 都无法满足。这时候就涉及到大数处理的问题上了。

下面介绍常规的大数阶乘。

 

3.利用数组存结果。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. int main()  
  3. {  
  4.     int n;  
  5.     int a[9000]; //确保保存最终运算结果的数组足够大  
  6.      int digit = 1; //位数  
  7.      int temp;   //阶乘的任一元素与临时结果的某位的乘积结果  
  8.      int i, j, carry; //carry:进位  
  9.   
  10.      printf("please in put n:\n");  
  11.     scanf("%d",&n);  
  12.     a[0] = 1;   //将结果先初始化为1  
  13.   
  14.     for ( i=2; i<=n; i++ )  //开始阶乘,阶乘元素从2开始依次"登场"  
  15.     {  //按最基本的乘法运算思想来考虑,将临时结果的每位与阶乘元素相乘  
  16.          for( j=1, carry=0;  j<=digit; j++ )  
  17.         {  
  18.             temp = a[j-1] * i + carry; //相应阶乘中的一项与当前所得临时结果的某位相乘(加上进位)  
  19.               a[j-1] = temp % 10; //更新临时结果的位上信息  
  20.               carry = temp / 10; //看是否有进位  
  21.          }  
  22.         while(carry)  
  23.         {    //如果有进位  
  24.               a[++digit-1] = carry % 10; //新加一位,添加信息。位数增1  
  25.             carry = carry / 10; //看还能不能进位  
  26.          }  
  27.     }  
  28.     printf("n ! = ");    //显示结果  
  29.     for(j = digit; j >=1;j--)  
  30.     {  
  31.         printf("%d",a[j-1]);  
  32.     }  
  33.     printf("\n");  
  34.     return 0;  
  35. }  


 

这种大数阶乘算法也比较常规,目前水平能看懂。 

具体思路代码中的注释也比较详细,就不重复了。  还是模拟笔算的过程。

 

下面附带两个大牛的算法 , 虽然现在还看不懂,但是先mark一下。以后慢慢琢磨。

 

4. 大牛算法一

出处 :  http://www.cnblogs.com/xianghang123/archive/2011/08/24/2152430.html

 

[cpp]  view plain copy
  1. #define N 400  
  2. long a[8916]={1,0},n,i,c,len;   
  3. int main(void)    
  4. {   
  5.     n=N;   
  6.     for ( len=1;n>1; n--)   
  7.     {   
  8.         for (c=0,i=0; i<len;i++ )   
  9.         {   
  10.             a[i]= ( c+= a[i]*n ) % 10000; c/=10000;   
  11.         }   
  12.            
  13.         ((a[i]=c)>0)?len++:0;   
  14.   
  15.     }      
  16.     for( len--,printf("%d",a[len--]);len>=0; len--) printf("%04d",a[len]);   
  17.            
  18.     return 0;   
  19. }  


 

【解释】

 for ( len=1;n>1; n--)     //把len的长度初始为1,因为数组中已经有一个元素了a[0]=1
 { 
   for (c=0,i=0; i<len;i++ ) //c初始为0,一开始还没运算哪来的进位,这是个内层循环,数组a中的len
                          //个元素都必须参与运算,都必须*n,这就是下面a[i]*n的来由

     { 
           a[i]= ( c+= a[i]*n ) % 10; c/=10;   //c是进位,不用说了,c+=a[i]*n,a每个元素与n
                                                //相乘必须考虑低位是否有进位,有就加起来
     }

   ((a[i]=c)>0)?len++:0;  //最后一个元素也有进位吗,有的话就在当前的元素的下个数组位置直接等于进位值,并
                          // 且数组的元素值 要加1,没有的话什么都不干 ,光一个0什么都不是
                    
  }

 

 

 

5.大牛算法二

出处:http://bbs.csdn.net/topics/390025206

 

[cpp]  view plain copy
  1. int a[100000]={1},n,i,c,m=1;  
  2. main()  
  3. {  
  4.     scanf("%d",&n);  
  5.     for(;n;n--)  
  6.     {  
  7.         for(c=i=0;i<m||c;)  
  8.             a[i++]=(c+=a[i]*n)%10,c/=10;m=i;  
  9.     }  
  10.     for(;m;)  
  11.         putch(a[--m]+48);  
  12. }  

 

还有关于大数阶乘另有一个斯特林公式,不过这个是估算的值,并不是精确值,n的值越大,他的结果越精确。大家可以自己学习一下。

 

另外,网上关于大数阶乘的讨论也比较多。我也google了一些,学习后,感觉下面几个比较有意义。

还是先mark下。 便于以后温习。

http://www.cnblogs.com/qlwy/archive/2012/07/18/2598028.html

 

http://blog.csdn.net/hikaliv/article/details/4242988

 

http://blog.csdn.net/yxnk/article/details/1665052

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值