我遇到了以下用于计算大阶乘(最大为100的阶乘)的程序。.有人可以向我解释该算法中使用的基本思想吗?我只需要知道在计算阶乘中实现的数学即可。
#include <cmath> #include <iostream> #include <cstdlib> using namespace std; int main() { unsigned int d; unsigned char *a; unsigned int j, n, q, z, t; int i,arr[101],f; double p; cin>>n; p = 0.0; for(j = 2; j <= n; j++) p += log10(j); d = (int)p + 1; a = new unsigned char[d]; for (i = 1; i < d; i++) a[i] = 0; //initialize a[0] = 1; p = 0.0; for (j = 2; j <= n; j++) { q = 0; p += log10(j); z = (int)p + 1; for (i = 0; i <= z/*NUMDIGITS*/; i++) { t = (a[i] * j) + q; q = (t / 10); a[i] = (char)(t % 10); } } for( i = d -1; i >= 0; i--) cout << (int)a[i]; cout<<"\n"; delete []a; return 0; }
注意
n! = 2 * 3 * ... * n
以便
log(n!) = log(2 * 3 * ... * n) = log(2) + log(3) + ... + log(n)
这很重要,因为如果k是正整数,则的上限log(k)是的以10为底的表示形式的位数k。因此,这些代码行正在计算中的位数n!。
k
log(k)
n!
p = 0.0; for(j = 2; j <= n; j++) p += log10(j); d = (int)p + 1;
然后,这些代码行分配空间来容纳以下数字n!:
a = new unsigned char[d]; for (i = 1; i < d; i++) a[i] = 0; //initialize
然后我们只做小学乘法
p = 0.0; for (j = 2; j <= n; j++) { q = 0; p += log10(j); z = (int)p + 1; for (i = 0; i <= z/*NUMDIGITS*/; i++) { t = (a[i] * j) + q; q = (t / 10); a[i] = (char)(t % 10); } }
外部循环从运行j从2到n,因为在我们将乘当前结果中表示由数字的每个步骤a通过j。内循环是年级乘法算法,其中我们将每个数字乘以j并在q必要时将结果带入。
j
2
n
a
q
该p = 0.0嵌套循环和前p += log10(j)内环路只是跟踪的位数的答案为止。
p = 0.0
p += log10(j)
顺便说一句,我认为程序的这一部分存在错误。循环条件应该是i < z没有i <= z,否则我们会写过去的结束a时z == d,这将是肯定的,当发生j == n。因此更换
i < z
i <= z
z == d
j == n
for (i = 0; i <= z/*NUMDIGITS*/; i++)
通过
for (i = 0; i < z/*NUMDIGITS*/; i++)
然后我们只打印数字
for( i = d -1; i >= 0; i--) cout << (int)a[i]; cout<<"\n";
并释放分配的内存
delete []a;