EDIT
I am sorry if I upset some of you. My only intention was to show a way how to avoid a stack overflow. I probably should have written a full code example instead of just a small piece of a quickly written and rough code excerpt.
This code
- avoids recursion as I use calculate the required values iteratively.
- includes memoization as Values already calculated are stored away and retrieved if already calculated
- also includes a stopwatch, so you can see that memoization works properly
...umm... if you run it make sure you set your command shell window to have a buffer of 9999 lines... the usual 300 will not be enough to run through the results of the below program...
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace ConsoleApplication1
{
class Program
{
static Stopwatch w = new Stopwatch();
static Faculty f = Faculty.GetInstance();
static void Main(string[] args)
{
Out(5);
Out(10);
Out(-5);
Out(0);
Out(1);
Out(4);
Out(29);
Out(30);
Out(20);
Out(10000);
Out(20000);
Out(19999);
Console.ReadKey();
}
static void Out(BigInteger n)
{
try
{
w.Reset();
w.Start();
var x = f.Calculate(n);
w.Stop();
var time = w.ElapsedMilliseconds;
Console.WriteLine(String.Format("{0} ({2}ms): {1}", n, x, time));
}
catch (ArgumentException e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("\n\n");
}
}
I declare
- 1 static variable "instance" in the Faculty class to a store a singleton. That way as long as your program is running, whenever you "GetInstance()" of the class you get the instance that has stored all values already calculated.
- 1 static SortedList which will hold all the values already calculated
In the constructor I also add 2 special values of the list 1 for inputs 0 and 1.
public class Faculty
{
private static SortedList<BigInteger, BigInteger> _values;
private static Faculty _faculty {get; set;}
private Faculty ()
{
_values = new SortedList<BigInteger, BigInteger>();
_values.Add(0, 1);
_values.Add(1, 1);
}
public static Faculty GetInstance() {
_faculty = _faculty ?? new Faculty();
return _faculty;
}
public BigInteger Calculate(BigInteger n)
{
// check if input is smaller 0
if (n < 0)
throw new ArgumentException(" !!! Faculty is not defined for values < 0 !!!");
// if value is not already calculated => do so
if(!_values.ContainsKey(n))
Faculties(n);
// retrieve n! from Sorted List
return _values[n];
}
private static void Faculties(BigInteger n)
{
// get the last calculated values and continue calculating if the calculation for a bigger n is required
BigInteger i = _values.Max(x => x.Key),
result = _values[i];
while (++i <= n)
{
CalculateNext(ref result, i);
// add value to the SortedList if not already done
if (!_values.ContainsKey(i))
_values.Add(i, result);
}
}
private static void CalculateNext(ref BigInteger lastresult, BigInteger i) {
// put in whatever iterative calculation step you want to do
lastresult = lastresult * i;
}
}
}