为什么这个 BigInteger 值会导致堆栈溢出异常? C#

Why does this BigInteger value cause a stack overflow exception? C#

我在 C# 中使用 BigInteger 与阶乘函数相关。该程序的计算速度快如闪电,达到 5000!,但在 10000! 时出现溢出错误。根据wolfram alpha,10000!大约是

10000! = 2.8 x 10^35659

this post 可以看出,BigInteger 存储在 int[] 数组中。如果我正确解释 int 类型,它使用 4 个字节,即 10000!使用大约 4 x log10(2.8 x 10^35659) = 142636 个字节,其中我使用 log10(n)(以 10 为底的对数)作为 n 的位数的近似值。这只有 143 MB,但我仍然遇到堆栈溢出异常。为什么会这样?

using System;
using System.Numerics;

class Program
{
    static void Main()
    {
        BigInteger hugeFactorial = Calculations.Factorial(5000);
    }
}

class Calculations
{
    public static BigInteger Factorial(int n)
    {
        if (n == 1) return n;
        else return n*Factorial(n - 1);
    }
}

Factorial 的递归调用导致足够大的调用堆栈的计算器溢出。你的呼唤10000!很可能达到那个目标。您可能必须将实现更改为迭代算法以修复溢出。

线程的默认堆栈大小为 1 MB。您可以在创建新线程时更改它。我会把你的代码写成(不阻塞调用线程):

TaskCompletionSource<BigInteger> tcs = new TaskCompletionSource<BigInteger>();
var t = new Thread(() => 
    {
        var res = Calculations.Factorial(10000);
        tcs.SetResult(res);
    }, 
    1024*1024*16 //16MB stack size
);
t.Start();
var result = await tcs.Task;
Console.Write(result);

正如loopedcode所说,您应该至少使用迭代算法来计算阶乘。

public static BigInteger Factorial(int n)
{
    BigInteger result = 1;
    for (int i = 2; i <= n; i++)
    {
        result *= i;
    }
    return result;
}

还有更高效的算法 (look here)。