Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am using BigInteger in C# in connection with the factorial function. The program has a lightning fast calculation of 5000!, but has an overflow error at 10000!. According to wolfram alpha, 10000! is approximately

10000! = 2.8 x 10^35659

From what I can tell from this post, a BigInteger is stored in an int[] array. If I interpret the int type correctly, it uses 4 bytes, meaning that 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. This is only 143 MB, but I still get a stack overflow exception. 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);
    }
}
like image 622
HowDoICSharply Avatar asked Nov 21 '15 22:11

HowDoICSharply


People also ask

What causes a stack overflow exception?

A StackOverflowException is thrown when the execution stack overflows because it contains too many nested method calls. using System; namespace temp { class Program { static void Main(string[] args) { Main(args); // Oops, this recursion won't stop. } } }

What is stack overflow and how does it occur?

A stack overflow is a type of buffer overflow error that occurs when a computer program tries to use more memory space in the call stack than has been allocated to that stack.


2 Answers

Default stack size for threads is 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);
like image 159
Eser Avatar answered Sep 27 '22 19:09

Eser


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

like image 33
ApceH Hypocrite Avatar answered Sep 27 '22 17:09

ApceH Hypocrite