简体   繁体   English

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

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

I am using BigInteger in C# in connection with the factorial function. 我在C#中使用BigInteger与factorial函数有关。 The program has a lightning fast calculation of 5000!, but has an overflow error at 10000!. 该程序闪电般快速计算5000!,但在10000时出现溢出错误! According to wolfram alpha , 10000! 根据wolfram alpha ,10000! is approximately 是约

10000! 10000! = 2.8 x 10^35659 = 2.8 x 10 ^ 35659

From what I can tell from this post , a BigInteger is stored in an int[] array. 从我在这篇文章中可以看出,BigInteger存储在int[]数组中。 If I interpret the int type correctly, it uses 4 bytes, meaning that 10000! 如果我正确解释int类型,它使用4个字节,意味着10000! uses about 4 x log10(2.8 x 10^35659) = 142636 bytes, where I use log10(n) (the log to base 10) as an approximation to the number of digits of n. 使用大约4 x log10(2.8 x 10^35659) = 142636字节,其中我使用log10(n) (对数为10的对数)作为n的位数的近似值。 This is only 143 MB, but I still get a stack overflow exception. 这只有143 MB,但我仍然得到堆栈溢出异常。 Why does this happen? 为什么会这样?

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);
    }
}

Default stack size for threads is 1 MB . 线程的默认堆栈大小为1 MB You can change it while creating a new thread. 您可以在创建新线程时更改它。 I would write your code as(without blocking the calling thread): 我会把你的代码编写为(不阻塞调用线程):

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);

As loopedcode said you should use at least iteration algorithm to calculate factorial. 正如循环代码所说,你应该使用至少迭代算法来计算阶乘。

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

There are even more efficient algorithms ( look here ). 有更高效的算法( 请看这里 )。

Recursive call of Factorial results in stackoverflow for a large enough call stack. Factorial递归调用导致堆栈Factorial足够大的调用堆栈。 Your call for 10000! 你的10000号召唤! is likely hitting that mark. 很有可能达到这个标准。 You will probably have to change your implementation to iterative algorithm to fix overflow. 您可能必须将实现更改为迭代算法以修复溢出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM