C#
pi calculation
programming
loops
numerical methods

How to calculate pi to N number of places in C using loops

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Calculating pi "to N places" can mean two different things: approximating pi numerically, or producing exactly N correct decimal digits. In C#, simple loop-based series can approximate pi well enough for demonstration, but they do not scale well for high-precision digit generation.

Start With the Right Expectation

If you use double, you only get about 15 to 17 decimal digits of precision no matter how many loop iterations you run. If you use decimal, you get more base-10-friendly precision, but still far less than arbitrarily many digits.

So a loop can approximate pi, but if you truly need hundreds or thousands of digits, you need arbitrary-precision arithmetic and a more advanced algorithm.

A Better Simple Series Than Leibniz

The Gregory-Leibniz series is famous but painfully slow. A better introductory loop-based option is the Nilakantha series:

pi = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - ...

It still converges by iteration, but much faster than Leibniz.

Here is a runnable C# example.

csharp
1using System;
2
3class Program
4{
5    static decimal CalculatePi(int terms)
6    {
7        decimal pi = 3m;
8        decimal sign = 1m;
9
10        for (int i = 2; i < 2 + terms * 2; i += 2)
11        {
12            decimal term = 4m / (i * (i + 1m) * (i + 2m));
13            pi += sign * term;
14            sign *= -1m;
15        }
16
17        return pi;
18    }
19
20    static void Main()
21    {
22        decimal pi = CalculatePi(100000);
23        Console.WriteLine(pi);
24    }
25}

This uses decimal instead of double so the printed output is a bit friendlier for base-10 display, but it is still not an arbitrary-precision solution.

Formatting to N Decimal Places

If your goal is just to print the approximation with N digits after the decimal point, format the result explicitly.

csharp
1using System;
2
3class Program
4{
5    static void Main()
6    {
7        double piApprox = Math.PI;
8        int digits = 8;
9        Console.WriteLine(piApprox.ToString($"F{digits}"));
10    }
11}

That prints N places, but it does not create new mathematical precision. It only formats the number you already have.

Why More Loops Stop Helping

Once you hit the precision ceiling of the numeric type, adding more loop iterations only burns CPU time. That is why people sometimes run a million iterations and still do not get more correct digits.

The bottlenecks are:

  • the convergence speed of the series
  • the precision of the numeric type
  • rounding error accumulated during repeated operations

For small educational programs, this is fine. For serious high-precision work, it is not.

If You Truly Need Many Digits

For real digit generation, use:

  • arbitrary-precision libraries
  • algorithms such as Machin-like formulas, Chudnovsky, or spigot-style methods
  • data structures designed for big-number arithmetic

That is a different problem from "use a loop and print a decimal." It requires representing more digits than built-in numeric types can store.

A Comparison With Leibniz

Leibniz is often taught first because it is simple.

csharp
1static double LeibnizPi(int terms)
2{
3    double sum = 0.0;
4    for (int k = 0; k < terms; k++)
5    {
6        double term = 1.0 / (2 * k + 1);
7        sum += (k % 2 == 0) ? term : -term;
8    }
9    return 4 * sum;
10}

This is mathematically correct, but it converges so slowly that it is a poor choice if your goal is decimal-place accuracy rather than learning how alternating series work.

Common Pitfalls

The biggest mistake is equating formatted output with actual precision. Printing 50 decimal places from a double does not mean you computed 50 correct digits.

Another mistake is choosing an extremely slow series such as Leibniz and assuming the language is the problem when convergence is actually the issue.

A third issue is asking built-in numeric types to do arbitrary-precision work. C# numeric primitives were not designed for that.

Finally, if the requirement really is "exactly N digits," define whether N means decimal places in a formatted approximation or provably correct digits from a high-precision algorithm.

Summary

  • A simple loop can approximate pi, but not to unlimited precision.
  • Nilakantha is a better teaching example than Leibniz for loop-based approximation.
  • 'double and decimal have fixed precision limits.'
  • Formatting to N places is not the same as computing N correct digits.
  • For many digits, use arbitrary-precision arithmetic and a faster formula.
  • Choose the algorithm based on whether the goal is education, approximation, or true high-precision computation.

Course illustration
Course illustration

All Rights Reserved.