【问题标题】:i need to get the factorial of 1000000 in c我需要在 c 中获得 1000000 的阶乘
【发布时间】:2017-11-28 23:37:49
【问题描述】:
double factorial(int x) {
if (x >= 1)
    return x * factorial(x - 1);
else
    return 1;
}

当我尝试得到 1000000 的阶乘时,它会导致分段错误。请任何人都可以帮助我吗??

【问题讨论】:

  • 鉴于您可以使用大量库来表示值,因此递归函数会导致堆栈溢出。
  • 你知道这个数字有多大吗?提示:very, very large.
  • 首先,不要使用递归。其次,您需要澄清要求是什么,因为您要求的数字无法以任何合理的形式表示......
  • 如果你想支持这么大的数字,你需要一个大整数库。
  • 通过计算阶乘的以 10 为底的对数进行循环,让您了解它有多大。

标签: c factorial abstract-data-type


【解决方案1】:

添加一个答案,它不会给出该阶乘的精确值,而是给出该结果数的10的幂

为此,让我们使用 y = log10(x) 给出 x = 10y >y。

例如 log10(1000000) 是 6(6 个零,106)。 log10(9500) 约为 3.98,因为我们接近 104

那么log(a * b)log(a) + log(b),这在我们的例子中非常有用,因为fact(x)x*(x-1)*(x-2)*...*1)

现在正如@dbush 所说,您不能递归循环 1M 次,因为保存返回地址(和局部变量)的堆栈将很快溢出。所以让我们做一个循环来代替

double d,pow10 = 0.0;
for(d=1 ; d<=1000000 ; d++) pow10 += log10(d);
printf("Result is 10^ %.02lf\n", pow10);

做到了,结果是~105565708.92,一个有~5565709位数的数字...


您还可以使用 Gosper 的出色近似(在 Math SE 上讨论)

一个不需要循环的封闭公式,可以提供出色的阶乘近似。再次计算将达到限制,所以做 log10,有 log(ab) = b*log(a)

1000000*log(1000000) - 1000000*log(e) + log(sqrt((2000000+1/3)*PI))

也给出 ~5565708.92,阶乘为 ~105565708.92

【讨论】:

    【解决方案2】:

    您不能让函数递归调用自身 1000000 次。这很容易溢出堆栈,导致段错误。

    您需要切换到迭代解决方案:

    double factorial(int x)
    {
        double result = 1;
        while (x >= 1) {
            result *= x;
            x--;
        }
        return result;
    }
    

    另请注意,您没有足够的精度来存储此值的所有数字。为此,您需要使用像 GMP 这样的大数字库。

    【讨论】:

    • double 是否有意义,或者例如unsigned long longdouble好吗?
    • @pzaenger:1000000!比其中任何一个都大得多。
    • @pzaenger:1000000!大约有 5,565,709 位数字。你想到的是哪种整数类型?
    • @pzaenger:嗯,这两个都没有意义。你知道100万有多大吗!是??它有数百万位。 unsigned long long 可能有 64。double 的指数范围仅上升到 1024。即使 IEEE 四元精度也仅上升到 16384。没有办法表示 1000000 的近似值!没有具有巨大指数范围的自定义软浮点类型,并且没有很多 GB 内存就无法表示确切的值。
    • @R..:只有数百万位数,而不是数十亿。
    【解决方案3】:

    可以迭代计算任意大的阶乘,而无需使用库来处理大量数字。 我用 Java 编写了一个解决方案(针对 ProjectEuler 问题),我已经针对谷歌验证了高达 1000!,并运行了 5000!在 5 年前的桌面上不到一分钟(可能很慢,因为它正在控制台上显示输出。)。 不到 100 行代码,包括 cmets 和打印输出。 (不共享代码,因为这是 ProjectEuler 协议的一部分)。

    【讨论】:

    • 是的。很高兴知道是否有人问了这个问题,因为这种方法很有意义。我在高中时有一个家庭作业,老师希望我们编写一个可以在 16 位 CPU 上添加任意大数的程序(基本)你当然可以编写一个程序来通过存储值来计算阶乘,比如一长串数字或其他仿真。但是性能很糟糕,甚至对于这个简单的算术表达式也可能几乎无法使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-04
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多