import numpy as np
import matplotlib.pyplot as plt

# ── Función y derivadas exactas ──────────────────────────────
# f(x)  = x·sin(x²)
# f'(x) = sin(x²) + 2x²·cos(x²)
# f''(x)= 6x·cos(x²) - 4x³·sin(x²)
# En x=0: f=0, f'=0, f''=0  (función impar → derivadas pares nulas)

def f(x):
    return x * np.sin(x**2)

def df_exacta(x):
    return np.sin(x**2) + 2*x**2 * np.cos(x**2)

def d2f_exacta(x):
    return 6*x*np.cos(x**2) - 4*x**3 * np.sin(x**2)

# ── Fórmulas de diferencias finitas ─────────────────────────
# Todas vienen de truncar la serie de Taylor de f alrededor de x.

def adelante(f, x, h):
    # f'(x) ≈ [f(x+h) - f(x)] / h         Error: O(h)
    return (f(x + h) - f(x)) / h

def atras(f, x, h):
    # f'(x) ≈ [f(x) - f(x-h)] / h         Error: O(h)
    return (f(x) - f(x - h)) / h

def centrada_1(f, x, h):
    # f'(x) ≈ [f(x+h) - f(x-h)] / (2h)    Error: O(h²)  ← más precisa
    return (f(x + h) - f(x - h)) / (2*h)

def centrada_2(f, x, h):
    # f''(x) ≈ [f(x+h) - 2f(x) + f(x-h)] / h²   Error: O(h²)
    return (f(x + h) - 2*f(x) + f(x - h)) / h**2

# ── Parámetros ───────────────────────────────────────────────
x0 = 0.0
h  = 0.01

# Valores exactos
ex1 = df_exacta(x0)
ex2 = d2f_exacta(x0)

# Aproximaciones con h = 0.01
D_ad  = adelante(f, x0, h)
D_at  = atras(f, x0, h)
D_c1  = centrada_1(f, x0, h)
D_c2  = centrada_2(f, x0, h)

# ── Resultados en consola ────────────────────────────────────
sep = "=" * 58
print(sep)
print("  DIFERENCIAS FINITAS — f(x)=x·sin(x²)  en  x₀=0")
print(sep)

print(f"\n  Paso h = {h}\n")

print("  PRIMERA DERIVADA")
print(f"  {'─'*54}")
print(f"  {'Método':<22} {'Aprox':>12} {'Error abs':>14}")
print(f"  {'─'*54}")
for nombre, val in [("Adelante  O(h)", D_ad),
                    ("Atrás     O(h)", D_at),
                    ("Centrada  O(h²)", D_c1)]:
    print(f"  {nombre:<22} {val:>12.8f} {abs(ex1-val):>14.2e}")
print(f"  Exacta: {ex1}")

print(f"\n  SEGUNDA DERIVADA")
print(f"  {'─'*54}")
print(f"  {'Método':<22} {'Aprox':>12} {'Error abs':>14}")
print(f"  {'─'*54}")
print(f"  {'Centrada  O(h²)':<22} {D_c2:>12.8f} {abs(ex2-D_c2):>14.2e}")
print(f"  Exacta: {ex2}")

# ── Paso a paso con h = 0.01 ─────────────────────────────────
print(f"\n  CÁLCULO PASO A PASO  (h = {h})")
print(f"  {'─'*54}")
fp = f(x0 + h);  f0 = f(x0);  fm = f(x0 - h)
print(f"  f({x0+h})  = {fp:.8f}")
print(f"  f({x0})    = {f0:.8f}")
print(f"  f({x0-h}) = {fm:.8f}")
print(f"\n  f'(x₀) ≈ [{fp:.6f} - ({fm:.6f})] / (2×{h})")
print(f"         = {centrada_1(f,x0,h):.8f}")
print(f"\n  f''(x₀)≈ [{fp:.6f} - 2×{f0:.6f} + {fm:.6f}] / {h**2}")
print(f"         = {centrada_2(f,x0,h):.8f}")

# ── Tabla de convergencia ────────────────────────────────────
# Al reducir h×10, el error O(h²) debe caer ~100 veces.
print(f"\n  CONVERGENCIA — centrada O(h²)")
print(f"  {'─'*54}")
print(f"  {'h':>8}  {'f´ aprox':>12}  {'Error':>10}  {'Razón':>7}")
print(f"  {'─'*54}")
valores_h = [1e-1, 1e-2, 1e-3, 1e-4, 1e-5]
e_ant = None
for hi in valores_h:
    ap = centrada_1(f, x0, hi)
    er = abs(ex1 - ap)
    razon = f"{e_ant/er:>7.1f}" if (e_ant and er > 0) else "      —"
    print(f"  {hi:>8.0e}  {ap:>12.8f}  {er:>10.2e}  {razon}")
    e_ant = er if er > 0 else e_ant
print(sep)

# ── Gráficas ─────────────────────────────────────────────────
x = np.linspace(-2.5, 2.5, 1000)

fig, (panel_exacto, panel_zoom) = plt.subplots(1, 2, figsize=(13, 5))
fig.suptitle("Diferencias finitas — $f(x) = x\\,\\sin(x^2)$ en $x_0 = 0$",
             fontsize=13, fontweight='bold')

# ── Panel izquierdo: función y derivadas exactas ─────────────
panel_exacto.plot(x, f(x),        label='$f(x)$',    lw=2)
panel_exacto.plot(x, df_exacta(x),  label="$f'(x)$ exacta",  lw=1.5, ls='--')
panel_exacto.plot(x, d2f_exacta(x), label="$f''(x)$ exacta", lw=1.5, ls=':')
panel_exacto.axhline(0, color='k', lw=0.7)
panel_exacto.axvline(0, color='k', lw=0.7)
panel_exacto.set_xlim(-2.5, 2.5)
panel_exacto.set_ylim(-6, 6)
panel_exacto.set_title("Función y derivadas exactas")
panel_exacto.set_xlabel("x")
panel_exacto.set_ylabel("y")
panel_exacto.legend(fontsize=9)
panel_exacto.grid(True, alpha=0.3)

# Marcamos x₀ = 0
panel_exacto.scatter([x0], [f(x0)], color='red', zorder=5, s=60)
panel_exacto.annotate(f'$x_0={x0}$', xy=(x0, f(x0)),
                      xytext=(0.3, 0.5), fontsize=9, color='red')

# ── Panel derecho: rectas tangentes aproximadas ──────────────
zoom = np.linspace(-0.15, 0.15, 400)

panel_zoom.plot(zoom, f(zoom), label='$f(x)$', lw=2.5)

# Recta tangente exacta en x₀ (pendiente = f'(x₀) = 0)
panel_zoom.axhline(f(x0), color='green', ls='-', lw=1.8,
                   label=f"Tangente exacta  $f'(0)={ex1:.4f}$")

# Tangente por diferencia hacia adelante
tang_ad = f(x0) + D_ad * (zoom - x0)
panel_zoom.plot(zoom, tang_ad, ls='--', lw=1.5,
                label=f"Adelante  $\\approx${D_ad:.4f}")

# Tangente por diferencia hacia atrás
tang_at = f(x0) + D_at * (zoom - x0)
panel_zoom.plot(zoom, tang_at, ls=':', lw=1.5,
                label=f"Atrás     $\\approx${D_at:.4f}")

# Tangente por diferencia centrada
tang_c = f(x0) + D_c1 * (zoom - x0)
panel_zoom.plot(zoom, tang_c, ls='-.', lw=1.5,
                label=f"Centrada  $\\approx${D_c1:.4f}")

# Puntos usados por la fórmula centrada
panel_zoom.scatter([x0-h, x0, x0+h],
                   [f(x0-h), f(x0), f(x0+h)],
                   color='red', zorder=5, s=50,
                   label=f'Puntos: $x_0±h$')

panel_zoom.axhline(0, color='k', lw=0.7)
panel_zoom.axvline(0, color='k', lw=0.7)
panel_zoom.set_title("Zoom en $x_0=0$: rectas tangentes aproximadas")
panel_zoom.set_xlabel("x")
panel_zoom.set_ylabel("y")
panel_zoom.legend(fontsize=8)
panel_zoom.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: