# ==========================================================
# Comparador de aproximaciones de PI (MicroPython)
# Métodos: Leibniz, Wallis, Euler, Nilakantha, Madhava, Machin
# Mide error vs math.pi y costo temporal en microsegundos.
# ==========================================================
import math
import time
# -----------------------------
# Helpers de benchmark
# -----------------------------
def bench(func, N):
t0 = time.ticks_us()
val = func(N)
dt = time.ticks_diff(time.ticks_us(), t0)
return val, dt
def abs_err(x, ref):
return x - ref if x >= ref else ref - x
# -----------------------------
# 1) Leibniz:
# pi = 4 * sum_{n=0..∞} (-1)^n/(2n+1)
# -----------------------------
def pi_leibniz(N):
s = 0.0
sign = 1.0
denom = 1.0
# N términos => n = 0..N-1
for _ in range(N):
s += sign / denom
sign = -sign
denom += 2.0
return 4.0 * s
# -----------------------------
# 2) Wallis (producto):
# pi/2 = Π_{n=1..∞} (2n/(2n-1))*(2n/(2n+1))
# => pi = 2 * producto
# -----------------------------
def pi_wallis(N):
p = 1.0
for n in range(1, N + 1):
a = 2.0 * n
p *= (a / (a - 1.0)) * (a / (a + 1.0))
return 2.0 * p
# -----------------------------
# 3) Euler (serie):
# sum_{n=0..∞} 2^n (n!)^2/(2n+1)! = pi/2
# => pi = 2 * sum
#
# Usamos recurrencia:
# t0 = 1
# t_{n+1} = t_n * [ 2*(n+1)^2 / ((2n+2)(2n+3)) ]
# -----------------------------
def pi_euler(N):
s = 0.0
t = 1.0 # n=0
# N términos => n = 0..N-1
for n in range(N):
s += t
# preparar t_{n+1}
np1 = n + 1
num = 2.0 * (np1 * np1)
den = (2.0 * n + 2.0) * (2.0 * n + 3.0)
t *= num / den
return 2.0 * s
# -----------------------------
# 4) Nilakantha:
# pi = 3 + 4*sum_{n=1..∞} (-1)^{n+1} / [(2n)(2n+1)(2n+2)]
# -----------------------------
def pi_nilakantha(N):
s = 0.0
sign = 1.0
for n in range(1, N + 1):
a = 2.0 * n
term = 1.0 / (a * (a + 1.0) * (a + 2.0))
s += sign * term
sign = -sign
return 3.0 + 4.0 * s
# -----------------------------
# 5) Madhava–Gregory:
# pi = sqrt(12) * sum_{n=0..∞} (-1)^n /[(2n+1)*3^n]
# -----------------------------
def pi_madhava(N):
s = 0.0
sign = 1.0
pow3 = 1.0 # 3^0
denom = 1.0
for _ in range(N):
s += sign * (1.0 / (denom * pow3))
sign = -sign
pow3 *= 3.0
denom += 2.0
return math.sqrt(12.0) * s
# -----------------------------
# 6) Machin:
# pi/4 = 4*arctan(1/5) - arctan(1/239)
# arctan(x) = sum_{n=0..∞} (-1)^n x^{2n+1}/(2n+1)
#
# Recurrencia para términos de arctan:
# t0 = x
# t_{n+1} = - t_n * x^2 * (2n+1)/(2n+3)
# -----------------------------
def arctan_series(x, N):
s = 0.0
t = x
x2 = x * x
# N términos => n=0..N-1
for n in range(N):
s += t
t *= -x2 * (2.0 * n + 1.0) / (2.0 * n + 3.0)
return s
def pi_machin(N):
a = arctan_series(1.0 / 5.0, N)
b = arctan_series(1.0 / 239.0, N)
return 4.0 * (4.0 * a - b)
# -----------------------------
# Tabla experimental
# -----------------------------
METHODS = [
("Leibniz", pi_leibniz),
("Wallis", pi_wallis),
("Euler", pi_euler),
("Nilakantha", pi_nilakantha),
("Madhava", pi_madhava),
("Machin", pi_machin),
]
def tabla_convergencia(N_list):
ref = math.pi
print("\n==== Comparativa experimental de PI (MicroPython) ====")
print("Referencia math.pi =", ref)
print("Columnas: Metodo | N | pi_aprox | error_abs | tiempo_us")
print("-" * 78)
for N in N_list:
print("\n--- N =", N, "---")
for name, f in METHODS:
val, dt = bench(f, N)
err = abs_err(val, ref)
# Formato compacto para consola serial
print("{:<11s} | {:>6d} | {:>12.10f} | {:>10.3e} | {:>8d}".format(
name, N, val, err, dt
))
# -----------------------------
# Programa principal
# -----------------------------
def main():
# Lista de N típica para ver convergencia + costo.
# Ajuste si su micro es más lento o más rápido.
N_list = [10, 50, 100, 300, 1000, 3000]
# Si desea, puede pedir N máximo por consola:
# maxN = int(input("N max (ej 3000): "))
# N_list = [10, 50, 100, 300, 1000, maxN]
tabla_convergencia(N_list)
print("\nTips rápidos:")
print("- Leibniz: muy lento (error cae ~1/N).")
print("- Machin: muy rápido (gran precisión con pocos términos).")
print("- Wallis: lento/moderado y multiplica mucho (costo alto por término).")
print("- Euler/Nilakantha/Madhava: intermedios; buenos para docencia y embebidos.")
main()