[Back to

 previous page] [Next Page

 in Series]

Ken Ward's Java Script Tutorial ...

Calculating Pi (Machin Formula)

The following program is a javascript program which calculates pi. You can enter the number of digits you want in the box, and choose whether to separate the digits with a space every 5 digits, or whether to add the count at the end of each line, or not. Try the program to see how this works.

On this page:

Even though this is a rather slow program, it calculates 1000 digits of pi in about 13 seconds (13.028 seconds on one occasion), on a slow computer. The time taken to calculate a given number of digits does not merely double on doubling the number of digits, but increases about fourfold. So we would expect 2000 digits to take four times as long. Internet Explorer gives a message saying the script seems to be running for a long time. Press "No" to continue, or "Yes" to abort. It reports 57.993 seconds for 2000 digits. To calculate to 5000 places, the program took 324.266 seconds, with Internet Explorer complaining twice.

The program doesn't round the final digit, but reports 5 more digits than requested, some of these five may be wrong (the last few digits calculated with the Machin formula will nearly always be wrong). The digits requrested will, however, be correct. You can check digits using the pi search.

The program was inspired by a c-program by Pascal Sebah.

Number of Digits:

Add Count: 
Add Spaces:

Answer appears here

A (Very Very) Short History Of Pi

Even though this program is slow, compared with the history of pi, it is utterly remarkable compared with the history of pi.

In 1666 Sir Isaac Newton calculated pi to 15 places. He used a formula of his own devising. This formula was extremely slow to converge, and I suspect that Newton may have spent months, or even years, rather than hours, calculating 15 places.

In 1706, John Machin proposed a formula that converged very quickly.

Using Machin's formula, in 1873, William Shanks, after many years of labour, published his calculation of  pi to 707 places.

A Frenchman called Dagbert, memorised pi to 707 places, indicating that he had used Shanks work. It was quite popular for some mathematics students to learn pi to many digits, using Shanks work. However, it was only in the 1930s that suspicians began to arise that Shanks had made an error. In fact, he had made an error in the 528th place, so the remaining 180 digits were wrong. Professor Aitken, a mathematician from New Zealand, recorded his chagrin when he discovered that learning 707 decimal places of pi had been in vain.

The above, while amusing, probably isn't true, even though it is told in many places and by many famous people, see Carey Bloodworth's interesting article, also available on site here.

In 1949, the computer ENIAC took 70 hours to compute the value of pi to 2037 decimal places.

In recent years, pi has been computed to 1.24 trillion places.

However, while errors in millions of paper and pencil errors are expected, errors also occur in computer computations. They may occur   because of transient errors and hardware errors (and software errors of course!). In serious work, you should check, check and check again.

The Code

The heavily commented code for the pi program follows.

<html>

<head>

<title>Pi Machin</title>

<script language="javascript" type="text/javascript">

<!--//

mess="";

//10^11 seems to be the maximum

//too high a figure for the base introduces errors

Base=Math.pow(10,11);

//num digits in each array item

cellSize=Math.floor(Math.log(Base)/Math.LN10);

//below is not used in this script

a=Number.MAX_VALUE;

MaxDiv=Math.floor(Math.sqrt(a));

function makeArray (n, aX, Integer) {

var i=0;

for (i=1; i<n; i++)

aX[i] = null;

aX[0] = Integer;

}

function isEmpty (aX) {

var empty=true

for (i=0; i<aX.length; i++)

if (aX[i])

{

empty= false;

break;

}

return empty;

}

//junior school math

function Add (n, aX,aY) {

carry=0

for (i=n-1; i>=0; i--) {

aX[i] += Number(aY[i])+Number(carry);

if (aX[i]<Base)

carry = 0;

else {

carry = 1;

aX[i] =Number(aX[i])- Number(Base);

}

}

}

//subtract

function Sub (n, aX,aY) {

for (i=n-1; i>=0; i--) {

aX[i] -= aY[i];

if (aX[i]<0) {

if (i>0) {

aX[i] += Base;

aX[i-1]--;

}

}

}

}

//multiply big number by "small" number

function Mul (n, aX, iMult) {

carry=0;

for (i=n-1; i>=0; i--) {

prod = (aX[i])*iMult;

prod += carry;

if (prod>=Base) {

carry = Math.floor(prod/Base);

prod -= (carry*Base);

}

else

carry = 0;

aX[i] = prod;

}

}

//divide big number by "small" number

function Div (n, aX, iDiv,aY) {

carry=0;

for (i=0; i<n; i++) {

//add any previous carry

currVal = Number(aX[i])+Number(carry*Base);

//divide

theDiv =Math.floor(currVal/iDiv);

//find next carry

carry = currVal-theDiv*iDiv;

//put the result of division in the current slot

aY[i] = theDiv;

}

}

//compute arctan

function arctan (iAng, n, aX) {

iAng_squared=iAng*iAng;

k=3; //k is the coefficient in the series 2n-1, 3,5..

sign=0;

makeArray (n, aX, 0); //aX is aArctan

makeArray (n, aAngle, 1);

Div (n, aAngle, iAng, aAngle); //aAngle = 1/iAng, eg 1/5

Add (n, aX, aAngle); // aX = aAngle or long angle

while (!isEmpty(aAngle)) {

Div (n, aAngle, iAng_squared, aAngle); //aAngle=aAngle/iAng_squared, iAng_squared is iAng*iAng

//mess+="iAng="+iAng+"; aAngle="+aAngle+"<br>";

Div (n, aAngle, k, aDivK); /* aDivK = aAngle/k */

if (sign)

Add (n, aX, aDivK); /* aX = aX+aDivK */

else Sub (n, aX, aDivK); /* aX = aX-aDivK */

k+=2;

sign = 1-sign;

}

mess+="aArctan="+aArctan+"<br>";

}

// Calculate pi

function calcPI (numDec) {

var ans="";

t1=new Date();

numDec=Number(numDec)+5;

iAng=new Array(10);

coeff=new Array(10);

arrayLength=Math.ceil(1+numDec/cellSize);

aPI = new Array(arrayLength);

aArctan = new Array(arrayLength);

aAngle=new Array(arrayLength);

aDivK=new Array(arrayLength);

//Pi/4 = 4*arctan(1/5)-arctan(1/239)

//coeff is an array of the coefficients

//the last item is 0!

coeff[0] = 4;

coeff[1] = -1;

coeff[2] = 0;

//iAng holds the angles, 5 for 1/5, etc

iAng[0] = 5;

iAng[1] = 239;

iAng[2] = 0;

makeArray (arrayLength, aPI, 0);

//Machin: Pi/4 = 4*arctan(1/5)-arctan(1/239)

makeArray(arrayLength,aAngle,0);

makeArray(arrayLength,aDivK,0);

for (var i=0; coeff[i]!=0; i++) {

arctan(iAng[i], arrayLength, aArctan);

//multiply by coefficients of arctan

Mul (arrayLength, aArctan, Math.abs(coeff[i]));

//mess+="mi="+coeff[i]+"<br>";

if (coeff[i]>0)

Add (arrayLength, aPI, aArctan);

else

Sub (arrayLength, aPI, aArctan);

//mess+="api="+aPI+"<br>";

}

//we have calculated pi/4, so need to finally multiply

Mul (arrayLength, aPI, 4);

//we have now calculated PI, and need to format the answer

//to print it out

sPI="";

tempPI="";

//put the figures in the array into the string tempPI

for (i=0;i<aPI.length;i++)

{

aPI[i]=String(aPI[i]);

//ensure there are enough digits in each cell

//if not, pad with leading zeros

if (aPI[i].length<cellSize&&i!=0)

{

while (aPI[i].length<cellSize)

aPI[i]="0"+aPI[i];

}

tempPI+=aPI[i];

}

//now put the characters into the string sPI

for (i=0;i<=numDec;i++)

{

//put the 3 on a different line, and add a decimal point

if (i==0)

sPI+=tempPI.charAt(i)+".<br>";

else

{

//split the long line up into manageable rows

if (document.getElementById("cbCount").checked)

addcount=" ("+(i)+")";

else

addcount="";

if (document.getElementById("cbSpace").checked)

thespace=" ";

else

thespace="";

if ((i)%50==0&&i!=0)

sPI+=tempPI.charAt(i)+addcount+"<br>";

else

if (i%5==0)

sPI+=tempPI.charAt(i)+thespace;

else

sPI+=tempPI.charAt(i);

}//i not zero

}

//now put the print-out together

//print our pi

ans+=("PI ("+numDec+")="+sPI+"<br>");

//Window's calculator Pi (for confirmation);

ans+=("Win PI=<br>3.1415926535897932384626433832795<br>");

t2=new Date();

timeTaken=(t2.getTime()-t1.getTime())/1000;

ans+="It took: "+timeTaken+" seconds";

//document.write(mess);

var myDiv=document.getElementById("d1");

myDiv.innerHTML=ans;

}

//-->

</script>

</head>

<body bgcolor="white">

<h1>Pi Machin</h1>

<form name="" id="" method="post" action="" enctype="text/plain" onsubmit="calcPI(this.t1.value);return false;">

Number of Digits:<br>

<input type="text" name="t1" id="t1" value="100" size="25" maxlength="25"><br>

Add Count:

<input type="checkbox" name="cbCount" id="cbCount" value="" checked="checked"><br>

Add Spaces:

<input type="checkbox" name="cbSpace" id="cbSpace" value="" checked="checked"><br>

<input type="button" value="Calculate Pi" onclick="calcPI(this.form.t1.value)">

</form>

<div id="d1">Answer appears here</div>

</body>

</html>