I was fiddling around with inscribed and circumscribed n-gons of a circle, and using a couple $\sin$ and $\tan$ formulas I came up with two algorithms that approximate $\pi$ pretty fast.
The first algorithm approximates $\pi$ from below: $$ \begin{align} &1. \text{ Let } p \leftarrow \frac{1}{2} \text{ and } n \leftarrow 4 \\ &2. \text{ Keep repeating: } p \leftarrow \frac{1-\sqrt{1-p}}{2} \text{ and } n \leftarrow 2n \\ &3. \ \pi \approx n\sqrt{p} \end{align} $$
The second algorithm approximates $\pi$ from above: $$ \begin{align} &1. \text{ Let } p \leftarrow 1 \text{ and } n \leftarrow 4 \\ &2. \text{ Keep repeating: } p \leftarrow \frac{-1+\sqrt{1+p^2}}{p} \text{ and } n \leftarrow 2n \\ &3. \ \pi \approx np \end{align} $$
Since the first alorithm will always be below $\pi$ and the second one will always be above $\pi$, we can easily determine which are the correct digits of the outputs.
For example after $50$ iterations of the $2$nd step in each algorithm I got the outputs of:
$$ \begin{align} &\pi \approx 3.141592653589793238462643383279248096286 \text{, and} \\ &\pi \approx 3.141592653589793238462643383280012460020\\ \end{align} $$ They align up to $$\pi \approx 3.1415926535897932384626433832$$ Meaning those digits of $\pi$ are certainly correct.
Here is a the code of these algorithms in Python $3.7$ using the MPMath package for mathematical preciseness:
import math
from mpmath import mpf, mpc, mp
mp.dps = 10000
def pi_approx_below(iterations,print_partial_results=False,significant_digits=40):
p = mpf(0.5)
n = mpf(4)
for i in range(iterations):
p = mpf((1-mp.sqrt(1-p))/2)
n = mpf(2*n)
if(print_partial_results):
print("Pi approximation number " + str(i+1) + ": "+ str(mp.nstr(n*mp.sqrt(p),significant_digits)))
return mp.nstr(n*mp.sqrt(p),significant_digits)
def pi_approx_above(iterations,print_partial_results=False,significant_digits=40):
p = mpf(1)
n = mpf(4)
for i in range(iterations):
p = mpf((-1+mp.sqrt(1+p ** 2))/p)
n = mpf(2*n)
if(print_partial_results):
print("Pi approximation number " + str(i+1) + ": "+ str(mp.nstr(n*p,significant_digits)))
return mp.nstr(n*p,significant_digits)
print(pi_approx_below(50))
print(pi_approx_above(50))
And its output was:
3.141592653589793238462643383279248096286
3.14159265358979323846264338328001246002
Question: Are these known algorithms?
Note: I won't add a proof of why the algoithms work (yet), if the algorithms aren't known. I'd like to keep that to myself for now. Although I doubt I'm the first one who discovered these.