How to calculate pi, using addition, subtraction, multiplication, and division.


Credit to Ani ...

π = 3.1415926535897932384626433832795...


“The roots of education are bitter, but the fruit is sweet.”

Aristotle.


Pi is a special number that tells us how big the outside-edge of any circle is compared to the width through its center.
>>> if 'width' or 'diameter' is 1 ...>>> then 'outside-edge' or 'circumference' is always 3.14159265358979323846264338327950288419716939 ... times bigger ...
We can calculate pi by slicing an imaginary pizza into ever smaller parts, counting how many slices we end up with, and then multiplying the number of pizza slices we have by how thin the crust is at the end of the thinnest slice of pizza.

Step 1.1 : "Let's begin by drawing a picture of a square box" ...


Step 1.2 : "Draw an X through the corners of the box, and then draw a dot in the middle" ...



Step 1.3 : "Draw a circle around the dot touching all the inside edges of the box" ...



Step 1.4 : "Highlight one pizza slice" ...



Step 1.5 : "Join the start and end points of the crust of the pizza slice with a straight line" ...



Step 1.6 : "Join a line from the center of the circle to the line you just drew" ...


Now, if we imagine the 'radius' of our circle to be '1', then it just so happens, from "The Pythagorean Theorem", that the length of the 'straight line' (or 'chord', drawn in green) joining the start and end points of the 'arc' (the 'crust of the pizza slice') formed by the quarter-circle (step 1.5) is equal to the square-root of 2 ...

<<< click the links to learn more... >>>

...
// if ...

L = "length"

// and ...

R = "radius"

// then ...

  ( L × L ) = ( R × R ) + ( R × R ) ...

  ( L × L ) = ( 1 × 1 ) + ( 1 × 1 ) ...

  ( L × L ) = ( 1 ) + ( 1 ) ...

  ( L × L ) = ( 2 ) ...

// thus ...

L = sqrt ( 2 )


Knowing the above to be true, we can be sure that half the length of the green line must be equal to [ sqrt ( 2 ) ÷ 2 ] , and that the length of the blue line that joins the middle of the green line to the center of the circle must also be equal to [ sqrt ( 2 ) ÷ 2 ] ...

R = "radius" = 1R = "radius" = 1L = "length" = sqrt ( 2 )[ sqrt(2) ÷ 2 ]

We can work out sqrt(2) through a process we'll call "repeated estimation and reduction of error" for now, but later on we'll delve deeper into the origin of the algorithm in order to improve our results.

// if ... 

estimate = 1.5

// then ...

error    = ( ( estimate * estimate ) - 2 ) = ( 2.25 - 2 ) = ( 0.25 )


If we subtract one-third of the error from our first rough estimate for the square-root of two we get a value that is a tiny step closer to the correct answer ...

// refine estimate ... 

estimate =   ( estimate - ( error / 3 ) )  = ( 1.5 - 0.25 / 3 ) = ( 1.4166666666666667 ) 

// recalculate error ... 

error    = ( ( estimate * estimate ) - 2 ) = ( ...        ... ) = ( 0.006944444444444642 ) 


Using JavaScript, we only need to repeat this procedure 12 times to obtain an answer that is accurate to 16 decimal places ...

// JavaScript : estimate sqrt(2)...

let results     = [ ] ;

// ...

let estimate    = 1.5 ;
let error       = 0.0 ;

// loop ...

for ( let i=0 ; i<16 ; i++ ) { 
  estimate      = ( estimate - ( error / 3 ) ) ;
  error         = ( ( estimate * estimate ) - 2 ) ;
  // ... 
  results [ i ] = { i , estimate , error } ;
  } 

// ...

window.alert ( JSON.stringify ( results ) ) ;

/*
results = [
  {"i": 0,"estimate":1.5               ,"error": 0.25                    },
  {"i": 1,"estimate":1.4166666666666667,"error": 0.006944444444444642    },
  {"i": 2,"estimate":1.4143518518518519,"error": 0.00039116083676260516  },
  {"i": 3,"estimate":1.4142214649062643,"error": 0.000022351801620246192 },
  {"i": 4,"estimate":1.4142140143057242,"error": 0.0000012782587113235877},
  {"i": 5,"estimate":1.414213588219487 ,"error": 7.310463701060144e-8    },
  {"i": 6,"estimate":1.4142135638512747,"error": 4.180923607322029e-9    },
  {"i": 7,"estimate":1.4142135624576335,"error": 2.391109532595692e-10   },
  {"i": 8,"estimate":1.41421356237793  ,"error": 1.3675283128122828e-11  },
  {"i": 9,"estimate":1.4142135623733716,"error": 7.820410985459603e-13   },
  {"i":10,"estimate":1.414213562373111 ,"error": 4.4853010194856324e-14  },
  {"i":11,"estimate":1.414213562373096 ,"error": 2.6645352591003757e-15  },
  {"i":12,"estimate":1.4142135623730951,"error": 4.440892098500626e-16   }, <<<
  {"i":13,"estimate":1.414213562373095 ,"error":-4.440892098500626e-16   },
  {"i":14,"estimate":1.4142135623730951,"error": 4.440892098500626e-16   },
  {"i":15,"estimate":1.414213562373095 ,"error":-4.440892098500626e-16   },
  ] ; 
*/



Step 2.1 : "Let's extend the blue line (drawn in Step 1.6) toward the nearest point on the circle, and draw a line (shown in orange) from that new point up to the start of the arc formed by the quarter-circle" ...



Step 2.2 : "Highlight one-eighth of the circle" ...


OK. Now let's devise a system to further subdivide this circle, using algebra ...

Step 3.1 : "Add [x,y] coordinates to the box" ...

[0,0][-1,-1][0,-1][+1,-1][+1,0][+1,+1][0,+1][-1,+1][-1,0]


Step 3.2 : "Label the center of the circle 'C', the start of the arc 'A', the point 'B' halfway between the line that joins the start of the arc and the end of the arc, and the point 'D' at coordinate [+1,0]" ...

[0,0][-1,-1][0,-1][+1,-1][+1,0][+1,+1][0,+1][-1,+1][-1,0]ABCD

We worked out that the length of the line BC = (sqrt(2)/2), and since it lies on the line CD whose coordinates are [[0,0],[1,0]] , then the coordinates of the point B must be [(sqrt(2)/2),0] , and as the length of the line AB = BC, then the coordinates of the point A must be [(sqrt(2)/2),-(sqrt(2)/2)] . So now we can work out that the point 'E', halfway between points A and D, is located at [ (1-BC)/2+BC , -AB/2 ] ...

A  = [ (sqrt(2)/2) , -(sqrt(2)/2) ]

AB = (sqrt(2)/2) = 0.7071067811865476
BC = (sqrt(2)/2) = 0.7071067811865476
...
E  = [ (1-BC)/2+BC , -AB/2 ]
   = [ ((1-0.7071067811865476)/2+0.7071067811865476) , (-0.7071067811865476/2) ]
   = [ 0.8535533905932737 , -0.3535533905932738 ]




[0,0][-1,-1][0,-1][+1,-1][+1,0][+1,+1][0,+1][-1,+1][-1,0]ABCDEF

Marking a new point 'F', which is equal to [E.x,0], and knowing that cosine of angle ECF = ( E.x / length ( EC ) ) and that sine of angle ECF = ( E.y / length ( EC ) ) , we can extend the line CE to the point of intersection 'Anext' with the circle at coordinates [ cosine ( ECF ) , sine ( ECF ) ] ...

// if ...

length ( EC )
  = sqrt ( E.x * E.x + E.y * E.y )
  = sqrt ( 0.8535533905932737 * 0.8535533905932737  + -0.3535533905932738 * -0.3535533905932738 ) 
  = sqrt ( 0.8535533905932737  ) 
  = 0.9238795325112867 

// then ... 

Anext 
  = [ cosine ( ECF ) , sine ( ECF ) ] 
  = [ ( E.x / length ( EC ) ) , ( E.y / length ( EC ) ) ] 
  = [ ( 0.8535533905932737 / 0.9238795325112867 ) , ( -0.3535533905932738 / 0.9238795325112867 ) ] 
  = [ 0.9238795325112867 , -0.3826834323650898 ] 

[0,0][-1,-1][0,-1][+1,-1][+1,0][+1,+1][0,+1][-1,+1][-1,0]ABCDEAnextF

Using point 'Anext' as the new starting point for our next round of subdivision of the circle, then the next point of intersection we are looking for is located at ...

// if ... 

A  = Anext = [ 0.9238795325112867 , -0.3826834323650898 ]

AB = -A.y = 0.3826834323650898 
BC =  A.x = 0.9238795325112867 
... 
E  = [ (1-BC)/2+BC , -AB/2 ] 
   = [ ((1-0.9238795325112867)/2+0.9238795325112867) , (-0.3826834323650898/2) ] 
   = [ 0.9619397662556434 , -0.1913417161825449 ] 

// and ... 

length ( EC )
   = sqrt ( E.x * E.x + E.y * E.y ) 
   = sqrt ( 0.9619397662556434 *  0.9619397662556434 + -0.1913417161825449 * -0.1913417161825449 ) 
   = sqrt ( 0.9619397662556433 ) 
   = 0.9807852804032304 

// then ...

Anext
   = [ cosine ( ECF ) , sine ( ECF ) ]
   = [ ( E.x / length ( EC ) ) , ( E.y / length ( EC ) ) ] 
   = [ ( 0.9619397662556434 / 0.9807852804032304 ) , ( -0.1913417161825449 / 0.9807852804032304 ) ] 
   = [ 0.9807852804032304 , -0.19509032201612828 ] 



[0,0][-1,-1][0,-1][+1,-1][+1,0][+1,+1][0,+1][-1,+1][-1,0]AAnext

From here we can create a function to automate the process of subdividing the circle into even smaller segments.

Let's start with a way to work out square-roots using repeated estimation and refinement :


// JavaScript : ... 

function sqrt ( _number ) {
  const target       = _number ; 
  let   estimate     =  target ;
  let   error        =       0 ;
  let   lastEstimate =      -1 ;
  // loop ...
  for ( let i=0 ; i<128 ; i++ ) {
    estimate         = ( estimate - ( error / 3 ) ) ;
    error            = ( ( estimate * estimate ) - target ) ; 
    if ( lastEstimate == estimate ) break ; else lastEstimate = estimate ; 
    } 
  return ( estimate ) ; 
  } ; 


We start by creating a sqrt function based on the same method we used earlier to estimate the square-root of 2. We can now pass a variable _number to our function, and our function will return an estimate of the square-root of that number. With this we can begin to build another function that can gather a list of points that increasingly subdivides our circle ...

function getPointsOfSubdivisionOfCircleWithRadiusOne ( _numberOfSubdivisionsFromStartingPoint ) { 

  // square-root function ... 

  function sqrt ( _number ) {
    const target         = ( _number ) ;
    let   error          = (       0 ) ; 
    let   estimate       = ( target  ) ;
    let   lastEstimate   = (      -1 ) ;
    let   i              = (       0 ) ;
    // loop ...
    while ( ++i<=128 ) { 
      error              = ( target - estimate * estimate ) / 2 * estimate ; 
      estimate           = ( target / estimate + estimate ) / 2            ; 
      if ( lastEstimate == estimate ) break ; else lastEstimate = estimate ;
      } 
    return ( sqrt.depth=i , sqrt.error=error , ( estimate ) ) ;
    } ; 

  // ...

  const results          = [ ] ; 

  // loop control variables ... 

  const length           = _numberOfSubdivisionsFromStartingPoint ; 
  let   i                =  0  ; 

  // initialize point A and set polygon edge counter to 8 ... 

  let A                  = { x:(+0.7071067811865476) , y:(-0.7071067811865476) } ; 
  let polygonEdgeCount   = ( 8 ) ; 
  while ( 
    results [ i ]        = {
      loop_index         : i ,
      polygon_edge_count : polygonEdgeCount ,
      point_A            : { 
        x                : A.x , 
        y                : A.y , 
        } , 
      square_root_depth  : sqrt.depth || null ,
      } , ( ++i<length ) { 
    const AB             = -A.y ; 
    const BC             =  A.x ; 
    // ...
    const E              = { x:((1-BC)/2+BC) , y:(-AB/2)      } ; 
    const EC             = ( sqrt (  E.x * E.x + E.y * E.y )  ) ;
    const A_next         = { x:( E.x / EC )  , y:( E.y / EC ) } ; 
    // ... 
    A                    = A_next ; 
    polygonEdgeCount    *= 2      ; 
    } return ( results ) ;
  } ; 

window.alert ( JSON.stringify(getPointsOfSubdivisionOfCircleWithRadiusOne(8)) ) ; 

/*
result = [ 
  {"loop_index":0,"polygon_edge_count":   8,"point_A":{"x":0.7071067811865476,"y":-0.7071067811865476  },"square_root_depth":null}, 
  {"loop_index":1,"polygon_edge_count":  16,"point_A":{"x":0.9238795325112867,"y":-0.3826834323650898  },"square_root_depth":  39}, 
  {"loop_index":2,"polygon_edge_count":  32,"point_A":{"x":0.9807852804032305,"y":-0.1950903220161283  },"square_root_depth":  33}, 
  {"loop_index":3,"polygon_edge_count":  64,"point_A":{"x":0.9951847266721969,"y":-0.09801714032956063 },"square_root_depth":  31}, 
  {"loop_index":4,"polygon_edge_count": 128,"point_A":{"x":0.9987954562051724,"y":-0.04906767432741803 },"square_root_depth":  31}, 
  {"loop_index":5,"polygon_edge_count": 256,"point_A":{"x":0.9996988186962042,"y":-0.024541228522912295},"square_root_depth":  29}, 
  {"loop_index":6,"polygon_edge_count": 512,"point_A":{"x":0.9999247018391446,"y":-0.01227153828571993 },"square_root_depth":  27}, 
  {"loop_index":7,"polygon_edge_count":1024,"point_A":{"x":0.9999811752826012,"y":-0.006135884649154478},"square_root_depth":  26}, 
  ] ;
*/


A[0]A[1]A[2]...A[n]CD

The property polygon_edge_count refers to 'the number of sides a regular polygon with edge length equal to line(A[n],D) would have if inscribed within the circle', (or in other words 'how many pizza slices we end up with').

For example, point A[0] has a polygon_edge_count of 8 :

A[0]A[1]A[2]...A[n]CD

Point A[1] has a polygon_edge_count of 16, and touches point A[0] :

A[0]A[1]A[2]...A[n]CD


Point A[2] has a polygon_edge_count of 32, and touches points A[1] and A[0] :

A[0]A[1]A[2]...A[n]CD


The more we subdivide the circle the smoother the polygon we can form, and the closer we get to being able to completely fill the area of the circle. To estimate pi, we multiply line(A[n],D).length by A[n].polygon_edge_count and divide the result by 2 (because if 'radius' = 1 then 'diameter' = 2). By adding estimates for pi to our results at the end of each step, we should see our figures getting progressively closer to the correct value.

...
while (
  results[i] = {
    ...
    estimate_for_pi : sqrt ( ( ( 1 - A.x ) * ( 1 - A.x ) ) + ( A.y * A.y ) ) * ( polygonEdgeCount / 2 ) ,
    } , ( ++i<length ) ) { 
  ...
  } 
... 


Unfortunately, this immediately reveals the inaccuracy of our square-root function :

...
{"loop_index":0,"polygon_edge_count":   8, ... "estimate_for_pi":3.0614674589207183 },
{"loop_index":1,"polygon_edge_count":  16, ... "estimate_for_pi":3.121445152258052  },
{"loop_index":2,"polygon_edge_count":  32, ... "estimate_for_pi":3.1365484048024714 },
{"loop_index":3,"polygon_edge_count":  64, ... "estimate_for_pi":3.139334447930833  },
{"loop_index":4,"polygon_edge_count": 128, ... "estimate_for_pi":3.057349536353745  }, <<<
{"loop_index":5,"polygon_edge_count": 256, ... "estimate_for_pi":2.4771509479556673 },
{"loop_index":6,"polygon_edge_count": 512, ... "estimate_for_pi":1.5304491620360035 },
{"loop_index":7,"polygon_edge_count":1024, ... "estimate_for_pi":0.8163808783331219 },
...


However, with help from Wikipedia, we can vastly improve our square-root function using "Heron's method" , and in so doing, we find that we arrive at a value for Pi that is accurate to 15 decimal places by loop_index 23 : (after which point the precision may appear to drift) :

// ...
function sqrt ( _number ) { 
  const target         = ( _number ) ;
  let   estimate       = (  target ) ;
  let   lastEstimate   = (      -1 ) ;
  let   error          = (       0 ) ;
  let   i              = (       0 ) ;
  // loop ...
  while ( ++i<=128 ) {
    error              = ( target - estimate * estimate ) / 2 * estimate ;
    estimate           = ( target / estimate + estimate ) / 2            ;
    if ( lastEstimate == estimate ) break ; else lastEstimate = estimate ;
    }
  return ( sqrt.depth=i , sqrt.error=error , ( estimate ) ) ;
  } ;

/* 
{"loop_index":23,"polygon_edge_count":   67108864, ... "estimate_for_pi":3.141592653589793}, <<< 
{"loop_index":24,"polygon_edge_count":  134217728, ... "estimate_for_pi":3.141592653589794},
{"loop_index":25,"polygon_edge_count":  268435456, ... "estimate_for_pi":3.141592653589794},
{"loop_index":26,"polygon_edge_count":  536870912, ... "estimate_for_pi":3.141592653589795},
{"loop_index":27,"polygon_edge_count": 1073741824, ... "estimate_for_pi":3.141592653589795},
{"loop_index":28,"polygon_edge_count": 2147483648, ... "estimate_for_pi":3.141592653589795},
{"loop_index":29,"polygon_edge_count": 4294967296, ... "estimate_for_pi":3.141592653589795},
{"loop_index":30,"polygon_edge_count": 8589934592, ... "estimate_for_pi":3.141592653589795},
{"loop_index":31,"polygon_edge_count":17179869184, ... "estimate_for_pi":3.141592653589795},
...
*/



Conclusion :

The title to this essay is a little misleading. Although we did effectively work out pi to 15 decimal places using addition, subtraction, multiplication, and division, it wasn't easy, and in truth we relied heavily on JavaScript to automate all the algebraic calculations. We also sought help from Wikipedia when we needed to refine our square-root function, and we essentially shaped the whole approach to our solution using Geometry, by first drawing a square, drawing straight lines connecting opposite corners of the square, drawing a dot in the middle, drawing a circle around the dot, then slicing the circle into ever smaller segments using the Pythagorean theorem, Trigonometry, and Cartesian coordinates, before precisely measuring our narrowest slice and counting how many of those super-thin slices 'of pizza' would fit inside a circle.

Hopefully all the steps we took along the way toward our solution were made clear, but in all honesty it should also be mentioned that the author of this essay did not invent the solution above. He picked it up during his youth, after stumbling across a beautifully illustrated 1970s Open University video about maths that was broadcast on BBC2 (UK terrestrial television) during the 1980s, at a time when he was curious about such things. Today we are fortunate enough to have a wealth of independent programs on YouTube to choose from that may similarly enlighten our curiosity, as well as an AI powered search engine to help us out when we get stuck, but perhaps it is also worth noting that even Heron of Alexandria (the Ancient Greek mathematician and engineer, who live 2000 years ago, from whom we obtained an extremely accurate method for calculating square-roots) referred to ancient Babylonian formulas (perhaps as much as 4000 years old) in his most famous book, "Metrica".




“We stand on the shoulders of giants.”

Sir Isaac Newton.




"Title" : ( "How to calculate pi, using addition, subtraction, multiplication, and division." ) ,
"Created" : ( "Fri May 05 2023 02:09:32 GMT+0100 (British Summer Time)" ) ,
"Published" : ( "Fri May 12 2023 11:14:49 GMT+0100 (British Summer Time)" ) ,
"Updated" : ( "Thu Jun 01 2023 08:50:58 GMT+0100 (British Summer Time)" ) ,
"Author" : [ "Dave Auguste" ] ,
"Assistants" : [ "Anika Auguste" , "Bing Chat" ] ,
"Commissions" : [ "@dave_on_fiverr" ] ,
"Support" : [ "buymeacoffee.com/daveauguste" ] ,