Kash Farooq's software development blog

.NET Developer

Calculating Pi in C# with series algorithms

Posted by Kash Farooq on July 17, 2011

People write applications to calculate Pi to thousands of decimal places – I decided to investigate how they do that.

Google took me to a post discussing using recursion to calculate Pi. Quite ironic considering the post is on Stack Overflow… Anyway, the post did provide me with plenty of links and algorithm names for me to refine my search and find a way to do it without recursion.

I soon found this: a collection of series algorithms to calculate Pi.

So, I picked an algorithm and started coding.

To get going quickly, I decided to just use the built in .NET value types (i.e. decimal, double). These clearly are not good enough if you want to calculate Pi to hundreds of decimal places, but they would do for now.

To check my algorithm implementation worked, I got Pi to a few thousand decimal places from the interweb :

public static class Pi {
    public const string PiAsString = "3.14159265358979323846264338327...etc";
    public static string Get(int numberOfDecimalPlaces) {
        return PiAsString.Substring(0, numberOfDecimalPlaces + 2);
    }
}

Leibniz-Gregory-Madhava Series

You can calculate Pi using the following:

In the code below, my base class property “PiCalculatedToRequiredPrecision” is, as the name suggests, there stop if I’ve reached my target number of digits. The “KeepGoing” property is used to bail out of the loop if I’ve done far too many iterations (which I keep track of in the Iteration property) and I have still not managed to get the required number of digits.

public class LeibnizGregoryMadhava:SeriesAlgorithmBase {
    public LeibnizGregoryMadhava(int numberOfDecimalPlaces) : base(numberOfDecimalPlaces) {}

    // Pi/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 .....

    public override decimal Calculate() {
        CurrentPi = 1;
        var multiplier = 1;
        var nextNumber = 3;

        decimal result = 1;
        while (KeepGoing) {
            multiplier = multiplier * -1;
            result = result + multiplier * (decimal)1 /(nextNumber);
            CurrentPi = result*4;
            if (PiCalculatedToRequiredPrecision)
            {
                break;
            }
            Iteration++;
            nextNumber += 2;
        }
        return CurrentPi;
    }
}

And now to run my algorithm a few times specifying a different precision each time:

LeibnizGregoryMadhava took 117 iterations and 6 milliseconds to calculate PI to 2 decimal places
LeibnizGregoryMadhava took 1686 iterations and 3 milliseconds to calculate PI to 3 decimal places
LeibnizGregoryMadhava took 10792 iterations and 22 milliseconds to calculate PI to 4 decimal places
LeibnizGregoryMadhava took 136119 iterations and 290 milliseconds to calculate PI to 5 decimal places
LeibnizGregoryMadhava took 1530010 iterations and 3358 milliseconds to calculate PI to 6 decimal places

Over 1.5 million iterations (and 3.4 seconds) to get to 6 decimal places!!

Time to try another algorithm.

Euler Series

public class Euler:SeriesAlgorithmBase {
    //pi^2 / 6 = 1 + 1/4 + 1/9 + ..... + 1/k^2

    public Euler(int numberOfDecimalPlaces) : base(numberOfDecimalPlaces) {}
    public override decimal Calculate() {
        decimal result = 0;
        Iteration = 1;
        while (KeepGoing)
        {
            long squared = Iteration * Iteration;
            result = result + (decimal)1/squared;
            CurrentPi = (decimal) Math.Sqrt((double) (result * 6));
            if (PiCalculatedToRequiredPrecision())
            {
                break;
            }
            Iteration++;
        }
        return CurrentPi;

    }
}

And the results:

Euler took 600 iterations and 74 milliseconds to calculate PI to 2 decimal places
Euler took 1611 iterations and 3 milliseconds to calculate PI to 3 decimal places
Euler took 10307 iterations and 22 milliseconds to calculate PI to 4 decimal places
Euler took 359863 iterations and 819 milliseconds to calculate PI to 5 decimal places
Euler took 1461054 iterations and 3319 milliseconds to calculate PI to 6 decimal places

Hmmm. Fewer iterations (just!) and 3.3 seconds to get to 6 decimal places.

I’m not going to break any world records with this code. Clearly I need to do more research.

Related posts

Advertisements

3 Responses to “Calculating Pi in C# with series algorithms”

  1. Simon Read said

    That series:
    pi/4=1-1/3+1/5-1/7+1/9-…
    is an old and famous series. It’s possibly the best and the worst way of calculating pi.
    I’m going to re-write it as
    pi = 4-4/3+4/5-4/7+4/9…

    This series is the worst because, as you saw, each extra digit needs ten times as much work as the previous digit.

    It’s best for a reason I haven’t ever seen mentioned. Here goes.
    Write down the partial sums as a series of numbers
    4
    4-4/3
    4-4/3+4/5
    4-4/3+4/5-4/7
    etc.

    Notice that as a series of numbers, they alternate.
    Hey! You think, what can I do to smooth out the alternation, leaving me with the genuine value underneath? OK, so let’s call the above sequence A.
    A1 = 4
    A2= 2.666
    A3= 3.4666
    etc.

    Now let’s invent B
    B(i) = (A(i)+A(i+1))/2
    so our B series has damped out the oscillations. Note that the B series is much more settled more quickly. You get more digits with less work.
    But of course, it still oscillates. So we do it again…

    C(i)=(B(i)+B(i+1))/2
    and the C series has even smaller oscillations.

    This is not the best way to get pi, but it is a vast improvement. It also shows that there are ways of taking an existing (badly-converging) series and doing something to make it converge better.

    Simon

  2. So, did you ever continue?

Sorry, the comment form is closed at this time.

 
%d bloggers like this: