Computing pi (on pi day!)

Computing pi (on pi day!)#

In observance of Pi Day (March 14), we worked out a numerical computation of the number \(\pi\).

../../_images/pi-plain.png

A circle inscribed in a square.#

We started with the observation that a circle inscribed in a square covers \(\pi/4\) of the square’s surface. Consider the arrangement shown to the right. We have a square whose edge has length \(2a\). Its surface area is \(4a^2\). A circle inscribed in that square, has a diameter also \(2a\) and therefore a radius \(a\). The surface of the circle is \(\pi r^2\) or, in this case, \(\pi a^2\).

The fraction of the square’s surface covered by the circle is given by:

\[\frac{\text{area of circle with radius}\ r=a}{\text{area of square with edge}\ 2a} = \frac{\pi a^2}{4a^2} = \frac{\pi}{4}\]

Any point inside the square has a \(\pi/4\) chance of also being inside the circle. And if we consider a sufficient number of points inside the square, at random, we expect about \(\pi/4\) of them to be inside the circle. In other words: we have a way of computing \(\pi\) by throwing random points inside a square surface! The process is simple:

using a square with an inscribed circle:
N <-- number of points thrown at random, inside square
M <-- number of points inside circle
return 4*(M/N) as approximation of pi

The first thing we need to do is to set up the square with an inscribed circle, in a way that we can manipulate computationally. Next we need a way to tell if a random point inside a square is also inside the circle. And, of course, we need a way to generate random numbers.

../../_images/pi.png

Setting up the computational model we need.#

The geometric set up is straight forward, and shown to the right. If our square has an edge with length \(2a\), the inscribed circle has a radius of \(a\). If we place these shapes at the center of \(x\)-\(y\) axes, any point inside the square can be described by coordinates \((x, y)\) such that \(-a\leq x\leq a\) and \(-a\leq y\leq a\).

Consider a point inside the square as shown in the figure. This point, at \((x_1, y_1)\) is also inside the circle. The distance of any point from the center is given by the Pythagorean theorem; in the case of the point at \((x_1, y_1)\), that distance is \(z_1 = \sqrt{x_1^2+y_1^2}\). We can tell that the point is inside the circle because \(z_1 \leq a\).

Now, we can begin putting together some code in Java.

public static double pi(int N) {
  int M = 0;  // how many points inside circle
  for (int i=0; i < N; i++) { // loop to throw N points
    // x = random number anywhere from -a to a
    // y = random number anywhere from -a to a
    double z = math.sqrt(x*x+y*y);  // distance of random point (x,y) from center
    if (z <= a)  // is distance less than radius?
      M++; // point is inside circle; count it.
  }
  return 4.0*((double)M/(double)N);  // approximate value of pi
}

The last thing we need to analyze is how to find a random number in the interval from \(-a\) to \(a\). Java can generate random numbers in the range from 0 to 1. The transform we want, should work as follows:

Java random number

random number between \(-a\) and \(a\)

0

\(-a\)

1/2

0

1

\(a\)

This can be accomplished with the following expression:

\[(\text{random number from} -a\ \text{to}\ a)\ =\ -a +2a\rho\]

where \(\rho\) is a Java-generated random number. The final code is shown below.

 1/**
 2 * Computes pi by throwing N points, at random, inside a square and counting how many
 3 * fall within an inscribed circle.
 4 *
 5 * @param N int number of random points to throw inside the square
 6 * @return an approximate value of pi
 7 */
 8public static double pi(int N) {
 9    // Set up a random number generator
10    Random rng = new Random();
11    // Radius of inscribed circle; also determines size of square
12    double r = 1.0;
13    // Initialize counter of points inside circle
14    int M = 0;
15    // Set up loop to try N random points
16    for (int i = 0; i < N; i++) {
17        // Obtain coordinates for random point
18        double x = -r + 2.0*r*rng.nextDouble();
19        double y = -r + 2.0*r*rng.nextDouble();
20        // Distance of random point from center
21        double z = Math.sqrt(x*x+y*y);
22        // If this point is within circle, update count
23        if (z <= r)
24            M++;
25    }
26    return 4.0*((double) M/(double) N);
27}  // method pi

Casting both M and N as double variables in the return statement is a bit redundant. It suffices to cast as double only one of them. Nevertheless, it makes the code appear more purposeful, at least in my eyes.