Search code examples
c#matheulers-number

Calculating the Euler's Number gives a limited number of decimals on C#


I'm trying to calculate the Euler's number (e = 2.718281828459045235) by doing a factorial function and then calling it to calculate the constant with a while loop. The problem is that I declare an i variable to make the loop work under the circumstance i<50, as seen below, and it gives me the following output:

The number of euler is: 2.7182818284590455

However, I want the program to output more decimals, but no matter how I increase the i<50 condition in the loop, it always gives the same amount of decimals.

I've tried to change the while loop's condition to i<150 and I modified the "long" variable to a "ulong" one, but nothing happens, it always gives the same output. Any idea how to change that?

Any kind of help will be appreciated, thank you!

My code:

using System;

namespace eulerNumber
{
    class eulerCalculator
    {

        public static double factorial(long n)
        {
            if (n == 0)
            {
                return 1;
            }

            else if (n == 1)
            {
                return 1;
            }
            else
            {
                return n * factorial(n - 1);
            }
        }
        static void Main(string[] args)
        {
            double addition = 0, i = 0;

            while(i<50)
            {
                addition = addition + (1 / factorial((long)i)); 
                i++;
            }
            Console.WriteLine("The number of euler is: " + addition);
        }
    }
}


Solution

  • A fairly simple improvement is to perform the addition starting from the smallest terms first, so they are similar in size, and the processor can perform the addition without as much loss of precision.

    Note: factorial(50) is 50 * factorial(49), and the last two terms are 1/factorial(49) + 1/factorial(50). Apply some algebra to get 1/factorial(49) + 1.0/50/factorial(49), which is (1 + 1.0/50) / factorial(49)

    Say you only calculate the numerator, and keep track of what factorial appears in the denominator without calculating it. Now you have two very nice properties:

    1. You never have to calculate numbers that overflow (like factorial(i)) and
    2. Whatever rounding error there is in the update equation, doesn't matter to the final answer, because it's an error in a term that's going to get divided some more and become even smaller

    That leads to the following code:

    double accumulator = 1.0;
    
    for( int i = 50; i > 0; --i )
    {
        accumulator = 1.0 + accumulator / i;
    }
    

    Demo: https://rextester.com/FEZB44588


    Extension to use .NET's BigInteger class allows us to have many more digits of precision

    BigInteger scale = BigInteger.Pow(10, 60);
    BigInteger accumulator = scale;
    
    for( int i = 75; i > 0; --i )
    {
        accumulator = scale + accumulator / i;
    }
    

    result (insert the decimal point):

    2.718281828459045235360287471352662497757247093699959574966967

    first 50 decimal places from Wikipedia:

    2.71828182845904523536028747135266249775724709369995...

    Note that Wikipedia's verbiage is slightly wrong, this is not the value rounded to 50 decimal places, these are the first 50 decimal digits of a sequence that continues