谁能解释这个计算大阶乘的算法?

Posted

技术标签:

【中文标题】谁能解释这个计算大阶乘的算法?【英文标题】:Can anyone explain this algorithm for calculating large factorials? 【发布时间】:2010-01-24 15:31:06 【问题描述】:

我遇到了以下用于计算大阶乘(数字大至 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;

【问题讨论】:

你是从哪里发现这个算法的?您应该始终包含此信息以提供正确的归属,但它也可能有助于回答问题。 如果这不是为什么编写可读代码是一大好处的倒数第二个例子,那么我不知道是什么。这段代码不值得解释,值得重写。 这个算法名称是什么? 恕我直言,有一个错误。应该是a = new unsigned char[d+1]; 【参考方案1】:

注意

n! = 2 * 3 * ... * n

这样

log(n!) = log(2 * 3 * ... * n) = log(2) + log(3) + ... + log(n)

这很重要,因为如果k 是一个正整数,那么log(k) 的上限就是k 的base-10 表示中的位数。因此,这些代码行正在计算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

嵌套循环前的p = 0.0 和循环内的p += log10(j) 只是跟踪到目前为止答案中的位数。

顺便说一句,我认为这部分程序存在错误。循环条件应该是i &lt; z 而不是i &lt;= z 否则我们将在z == d 时写到a 的末尾,这肯定会在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;

【讨论】:

确实 - 来自我的 +1。如果可以的话,我会付出更多。

以上是关于谁能解释这个计算大阶乘的算法?的主要内容,如果未能解决你的问题,请参考以下文章

n的阶乘中用多少个2,3,5,7因数

算法训练 阶乘

关于高精度阶乘

程序员面试金典-面试题 16.05. 阶乘尾数

十五:阶乘计算

阶乘计算 高精度