阶乘相关的算法及其C++实现

一:首先要了解高精度乘法的工作原理

阶乘指从1乘以2乘以3乘以4一直乘到所要求的数。C++中的阶乘亦是如此。有关阶乘的算法,不外乎两个方面:一是高精度计算;二是与数论相关。

一。 高精度计算阶乘

这实际上是最没有技术含量的问题,但是又会经常用到,所以还是得编写,优化它的计算。

首先看小于等于12的阶乘计算(计算结果不会超出32位范围):

 
 
  1. int factorial(int n) {  
  2. if (n == 1 || n == 0)  
  3. return 1;  
  4. return factorial(n-1)*n;  
  5. }  
  6.  

这个递归程序简单明了,非常直观,然而一旦n > 12,则超过32位int型的范围出现错误结果,所以上面这个递归程序仅适合n <= 12的阶乘计算,为了计算较大n的阶乘,需要将高精度乘法算法纳入到阶乘计算中来,高精度乘法过程可以如下简单的描述:(其中A * B = C,A[0], B[0], C[0]分别存储长度)

 
 
  1. for (i = 1; i <= A[0]; i++)  
  2. for (j = 1; j <= B[0]; j++) {  
  3. C[i+j-1] += A[i]*B[j]; // 当前i+j-1位对应项 + A[i] * B[j]  
  4. C[i+j] += C[i+j-1]/10; // 它的后一位 + 它的商(进位)  
  5. C[i+j-1] %= 10; // 它再取余即可  
  6. }  
  7. C[0] = A[0] + B[0];  
  8. while (C[0] > 1 && C[C[0]] == 0) C[0]--; // 去头0,获得实际C的长度 

有了这个高精度乘法之后,计算阶乘就可以简单的迭代进行:

for (i = 2; i <= n; i++) {

将i转换成字符数组;

执行高精度乘法:将上一次结果乘上i

}

C++实现的高精度算法如下所示:

#include <iostream>
using namespace std;

int main(int argc, char const *argv[])
{
	string a,b;
	cin>>a>>b;

   
	int *A = new int[a.length()+1]; 
	int *B = new int[b.length()+1];
	int *C = new int[a.length()+b.length()+1];

    for (int i = 0; i < a.length()+b.length()+1; ++i)
    {
    	C[i]=0;
    }
	C[0] = a.length()+b.length()+1;
    for (int i = 1, j = a.length()-1 ; i <= a.length(); ++i,--j)
    {
    	A[i] = a[j] - '0';	
    }
   
    for (int i = 1, j = b.length()-1 ; i <= b.length(); ++i,--j)
    {
    	B[i] = b[j] - '0';
    } 
	
	
	for (int i = 1; i <= a.length(); ++i)
	{
		/* code */
		for (int j = 1; j <= b.length(); ++j)
		{
			/* code */
			C[i+j-1] += A[i] * B[j];
			C[i+j] += C[i+j-1] / 10;
			C[i+j-1] %= 10;
		}
	}
	bool zero = 1;
	for (int i = a.length()+b.length(); i >= 1;--i)
	{ 
		if(C[i] ==0 && zero )
			continue;
		else 
		{
		  zero = 0;
		  cout<<C[i];
		}
	}
	cout<<endl;

	system("pause");
	return 0;
}

所以如果想求高精度的阶乘,做法是相同的 n! = 1*2*3*4*5*6*....n;

#include <iostream>
#include <cmath> 
using namespace std;

int main(int argc, char const *argv[])
{
	int n,temp,i,j,carry; //temp:阶乘的任一元素与临时结果的某位的乘积结果
  int count =1 ;              //count代表位数,carry代表进位
  cin>>n;
  int a[9999];
  a[0]=1;
  for ( i = 2; i <=n ; ++i)
  {
    for (j = 1,carry=0; j<= count;j++)
    {
      temp = a[j-1]*i+carry;
      a[j-1] = temp %10 ;
      carry = temp/10;
    }
    while(carry)
    {
      a[count++] = carry%10;
      carry/=10;
    }
  }
  for (int i = count;i>=1; i--)
  {
    cout<<a[i-1];
  }
  cout<<endl;
	system("pause");
	return 0;
}
二:还有一种数论的方法。

还没搞定.....

一种数组的大牛算法如下:

#define N 400
long a[8916]={1,0},n,i,c,len; 
int main(void)  
{ 
    n=N; 
    for ( len=1;n>1; n--) 
    { 
        for (c=0,i=0; i<len;i++ ) 
        { 
            a[i]= ( c+= a[i]*n ) % 10000; c/=10000; 
        } 
         
        ((a[i]=c)>0)?len++:0; 

    }    
    for( len--,printf("%d",a[len--]);len>=0; len--) printf("%04d",a[len]); 
         
    return 0; 
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值