The problem is that the maximum value of an int
(Int32
) is 2147483647
.
You already know that the value you are expecting is 12586269025
which exceeds this value.
The simple solution is to change the value data type to long
(Int64
) or Int128
if you want to go to 93 12200160415121876738
Int128 fib(int n, Dictionary<int, Int128> memo)
{
Console.WriteLine("{0} [{1}] {2}", n, memo.Count, memo.Count > 0 ? memo.Last().ToString() : "??");
if (memo.ContainsKey(n))
{
return memo[n];
}
if (n <= 2) return 1;
else
{
memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
return memo[n];
}
}
Console.WriteLine("Fib " + fib(7, new Dictionary<int, Int128>()));
Console.WriteLine("Fib " + fib(46, new Dictionary<int, Int128>()));
Console.WriteLine("Fib " + fib(50, new Dictionary<int, Int128>()));
Console.WriteLine("Fib " + fib(92, new Dictionary<int, Int128>()));
Console.WriteLine("Fib " + fib(93, new Dictionary<int, Int128>()));
Why does this matter, or more importantly, why doesn't this fail when the result of fib(n - 1, memo) + fib(n - 2, memo)
is greater than the maximum value the data type can hold?
The answer is that by default the C# compiler doesn't do that. There is a healthy discussion here: No overflow exception for int in C#? but it is something that we need to be mindful of as c# developers if we are dealing with integers of large magnitudes (positive and/or negative).
If you wrap the addition expression in checked()
then we can force this to fail with an exception at runtime, rather than leaving us with a seemingly valid value:
memo[n] = checked(fib(n - 1, memo) + fib(n - 2, memo))
;
