I've written this simplified code to compute Pi for educational/demonstration purposes.
These methods are based upon the generalized means: see a presentation on Pi and the AGM.
Archimedes' method gives linear convergence, which means you get two extra bits of precision per iteration.
Gauss's method gives quadratic convergence, which means your precision doubles every iteration.
One can wrap these methods in timers or print current results to see how they converge.
Archimedes' method could have been used to disprove a millennia of false claims about Pi. Alas, history.
import decimal
def pi_arc():
"""Archimedes c. ~230 B.C.E."""
a, b = D(3).sqrt() / D(6), D(1) / D(3)
pi = 0
while True:
an = (a + b) / 2
b = (an * b).sqrt()
a = an
piold = pi
pi = 2 / (a + b)
if pi == piold:
break
return D(str(pi)[:-3])
def pi_agm():
"""Gauss AGM Method c. ~1800 A.D. """
a, b, t = 1, D(0.5).sqrt(), 1 / D(2)
p, pi, k = 2, 0, 0
while True:
an = (a + b) / 2
b = (a * b).sqrt()
t -= p * (a - an)**2
a, p = an, 2**(k + 2)
piold = pi
pi = ((a + b)**2) / (2 * t)
k += 1
if pi == piold:
break
return D(str(pi)[:-3])
if __name__ == "__main__":
prec = int(input('Precision for Pi: '))
"""Plus 3 for error"""
decimal.getcontext().prec = prec + 3
D = decimal.Decimal
print(pi_arc())
print(pi_agm())