一:首先要了解高精度乘法的工作原理
阶乘指从1乘以2乘以3乘以4一直乘到所要求的数。C++中的阶乘亦是如此。有关阶乘的算法,不外乎两个方面:一是高精度计算;二是与数论相关。
一。 高精度计算阶乘
这实际上是最没有技术含量的问题,但是又会经常用到,所以还是得编写,优化它的计算。
首先看小于等于12的阶乘计算(计算结果不会超出32位范围):
- int factorial(int n) {
- if (n == 1 || n == 0)
- return 1;
- return factorial(n-1)*n;
- }
这个递归程序简单明了,非常直观,然而一旦n > 12,则超过32位int型的范围出现错误结果,所以上面这个递归程序仅适合n <= 12的阶乘计算,为了计算较大n的阶乘,需要将高精度乘法算法纳入到阶乘计算中来,高精度乘法过程可以如下简单的描述:(其中A * B = C,A[0], B[0], C[0]分别存储长度)
- for (i = 1; i <= A[0]; i++)
- for (j = 1; j <= B[0]; j++) {
- C[i+j-1] += A[i]*B[j]; // 当前i+j-1位对应项 + A[i] * B[j]
- C[i+j] += C[i+j-1]/10; // 它的后一位 + 它的商(进位)
- C[i+j-1] %= 10; // 它再取余即可
- }
- C[0] = A[0] + B[0];
- 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;
}