Integrales y cálculo integral · Tema 34

Verificación simbólica y exploración con JavaScript

Representá funciones como datos y como código, derivá primitivas para comprobar resultados, construí sumas de Riemann y aprendé a interpretar el error numérico sin confundir una aproximación con una demostración.

01 · El código como instrumento matemático

Verificar no significa delegar el razonamiento

Una computadora puede evaluar miles de puntos, producir aproximaciones y revelar patrones con rapidez. Sin embargo, el programa ejecuta las reglas que escribimos: si la fórmula, el dominio o el algoritmo son incorrectos, obtendremos resultados precisos para un problema equivocado.

≡

Verificación exacta

Manipula una representación algebraica y comprueba identidades.

≈

Verificación numérica

Compara valores aproximados dentro de una tolerancia.

?

Diagnóstico

Busca dónde, cuánto y por qué dos resultados dejan de coincidir.

En cálculo integral conviene combinar tres controles:

  • Derivar la primitiva propuesta y recuperar el integrando.
  • Comparar una integral definida con una aproximación por sumas de Riemann.
  • Revisar dominio, signos, unidades y orden de magnitud.

02 · Funciones como valores

JavaScript permite pasar una función a otra función

Una función de JavaScript puede recibirse como argumento, guardarse en una variable y evaluarse en diferentes puntos. Esta capacidad permite escribir algoritmos genéricos para derivar, integrar o muestrear.

function muestrear(f, puntos) {
  return puntos.map(x => ({ x, y: f(x) }));
}

const cuadrado = x => x ** 2;
const muestras = muestrear(cuadrado, [-2, -1, 0, 1, 2]);
console.table(muestras);

La función muestrear no necesita conocer la fórmula de f. Solo requiere que, dado un número, devuelva otro número. Esta interfaz será compartida por el derivador numérico y las sumas de Riemann.

Dos formas de representar una función
RepresentaciónVentajaLimitación
x => x ** 2Puede evaluar casi cualquier fórmula programable.No conserva explícitamente su estructura algebraica.
Coeficientes [0,0,1]Permite derivar un polinomio exactamente.Solo representa la familia prevista por el formato.

03 · Una representación simbólica acotada

Los coeficientes permiten derivar polinomios exactamente

Representemos a₀+a₁x+a₂x²+… con un arreglo [a₀,a₁,a₂,…]. Derivar consiste en transformar cada coeficiente aₖ en k·aₖ y bajar el exponente:

[a₀,a₁,a₂,a₃]  →  [a₁,2a₂,3a₃]
function derivarPolinomio(coeficientes) {
  if (coeficientes.length <= 1) return [0];
  return coeficientes.slice(1).map((coeficiente, indice) =>
    coeficiente * (indice + 1)
  );
}

function evaluarPolinomio(coeficientes, x) {
  return coeficientes.reduceRight(
    (acumulado, coeficiente) => acumulado * x + coeficiente,
    0
  );
}

const F = [7, -2, 0, 3];       // 7−2x+3x³
const derivada = derivarPolinomio(F);
console.log('Coeficientes de F\' :', derivada);
console.log('F\'(2) =', evaluarPolinomio(derivada, 2));

El resultado [-2,0,9] representa −2+9x². Dentro de esta representación, la transformación es simbólica: no aproxima valores ni elige un incremento h.

04 · Construir y comprobar primitivas

Integrar coeficientes invierte la derivación polinómica

Para integrar aₖxᵏ dividimos el coeficiente por k+1 y aumentamos el exponente. La constante de integración ocupa la primera posición:

[a₀,a₁,a₂]  →  [C,a₀,a₁/2,a₂/3]
function integrarPolinomio(coeficientes, constante = 0) {
  return [
    constante,
    ...coeficientes.map((coeficiente, indice) =>
      coeficiente / (indice + 1)
    )
  ];
}

function derivarPolinomio(coeficientes) {
  if (coeficientes.length <= 1) return [0];
  return coeficientes.slice(1).map((coeficiente, indice) =>
    coeficiente * (indice + 1)
  );
}

const f = [4, -3, 6];
const F = integrarPolinomio(f, 10);
console.log('Primitiva:', F);
console.log('Derivada recuperada:', derivarPolinomio(F));

La salida recupera exactamente [4,−3,6]. La constante elegida no afecta la verificación porque su derivada es cero.

05 · Verificar funciones generales

La diferencia central aproxima mejor que una diferencia unilateral

La definición de derivada sugiere aproximarla con un incremento pequeño. Una diferencia hacia adelante usa:

F′(x) ≈ [F(x+h)−F(x)]/h

La diferencia central toma información a ambos lados:

F′(x) ≈ [F(x+h)−F(x−h)]/(2h)

Para funciones suficientemente suaves, el error de truncamiento central disminuye como h², frente a h en la fórmula hacia adelante.

function derivadaCentral(F, x, h = 1e-5) {
  if (!(h > 0)) throw new RangeError('h debe ser positivo');
  return (F(x + h) - F(x - h)) / (2 * h);
}

const F = x => Math.sin(x) ** 2 / 2;
const f = x => Math.sin(x) * Math.cos(x);
const x = 0.8;
const aproximada = derivadaCentral(F, x);

console.log('F\'(x) aproximada:', aproximada);
console.log('f(x) exacta:', f(x));
console.log('error:', Math.abs(aproximada - f(x)));

Esta comprobación sirve aunque no hayamos programado reglas simbólicas para seno, potencias y composición.

06 · Error de truncamiento y redondeo

Un h más pequeño no siempre produce una respuesta mejor

Reducir h acerca el cociente a la definición de derivada y disminuye el error de truncamiento. Pero si h es extremadamente pequeño, F(x+h) y F(x−h) quedan casi iguales. Su resta pierde dígitos significativos debido al punto flotante.

Diferencia central de sen(x) en x=1, comparada con cos(1)
hEfecto dominante esperadoLectura
10⁻¹TruncamientoEl intervalo local todavía es demasiado ancho.
10⁻⁵EquilibrioSuele dar una aproximación muy buena.
10⁻¹⁵Redondeo y cancelaciónLa resta pierde precisión.
function derivadaCentral(F, x, h) {
  return (F(x + h) - F(x - h)) / (2 * h);
}

const exacta = Math.cos(1);
for (const h of [1e-1, 1e-3, 1e-5, 1e-8, 1e-12, 1e-15]) {
  const valor = derivadaCentral(Math.sin, 1, h);
  console.log({ h, valor, error: Math.abs(valor - exacta) });
}

Explorar una escala de pasos ayuda a distinguir una tendencia estable de un resultado accidental.

07 · Comparar números de punto flotante

La igualdad aproximada combina tolerancia absoluta y relativa

Exigir calculado === esperado suele ser demasiado estricto. Usar solo un error absoluto tampoco se adapta bien a magnitudes muy grandes. Una comparación robusta admite:

|a−b| ≤ toleranciaAbsoluta + toleranciaRelativa·max(|a|,|b|)
function casiIguales(a, b, absoluta = 1e-10, relativa = 1e-8) {
  if (!Number.isFinite(a) || !Number.isFinite(b)) return a === b;
  const escala = Math.max(Math.abs(a), Math.abs(b));
  return Math.abs(a - b) <= absoluta + relativa * escala;
}

console.log('0.1 + 0.2 frente a 0.3:', casiIguales(0.1 + 0.2, 0.3));
console.log('100000001 frente a 100000000:', casiIguales(100000001, 100000000));
console.log('1 frente a 1.01:', casiIguales(1, 1.01));

08 · Probar en un conjunto de puntos

Un verificador debe informar el peor caso

Para comparar F′ con f, conviene recorrer varios puntos del dominio, registrar el error y conservar el máximo. El objetivo no es devolver únicamente true o false, sino aportar información para diagnosticar.

function derivadaCentral(F, x, h = 1e-5) {
  return (F(x + h) - F(x - h)) / (2 * h);
}

function verificarPrimitiva(f, F, puntos, tolerancia = 1e-7) {
  const pruebas = puntos.map(x => {
    const esperado = f(x);
    const obtenido = derivadaCentral(F, x);
    const error = Math.abs(obtenido - esperado);
    return { x, esperado, obtenido, error, coincide: error < tolerancia };
  });
  return {
    coincide: pruebas.every(prueba => prueba.coincide),
    errorMaximo: Math.max(...pruebas.map(prueba => prueba.error)),
    pruebas
  };
}

const resultado = verificarPrimitiva(
  x => 1 / x,
  x => Math.log(x),
  [0.5, 1, 2, 5]
);
console.log(resultado);

Los puntos deben pertenecer al dominio y dejar espacio para evaluar x−h y x+h. Para ln(x) no corresponde probar x≤0.

09 · Volver a la definición de integral

Una suma de Riemann se implementa con una partición y una muestra

Dividimos [a,b] en n subintervalos de ancho:

Δx=(b−a)/n

En el subintervalo i, elegimos un punto izquierdo, derecho o medio y sumamos f(xᵢ*)Δx.

function sumaRiemann(f, a, b, n, metodo = 'medio') {
  if (!Number.isInteger(n) || n <= 0) {
    throw new RangeError('n debe ser un entero positivo');
  }
  const dx = (b - a) / n;
  const desplazamientos = { izquierda: 0, medio: 0.5, derecha: 1 };
  if (!(metodo in desplazamientos)) throw new Error('Método desconocido');

  let suma = 0;
  for (let i = 0; i < n; i += 1) {
    const x = a + (i + desplazamientos[metodo]) * dx;
    suma += f(x) * dx;
  }
  return suma;
}

const f = x => x ** 2;
console.log('Izquierda:', sumaRiemann(f, 0, 2, 8, 'izquierda'));
console.log('Punto medio:', sumaRiemann(f, 0, 2, 8, 'medio'));
console.log('Derecha:', sumaRiemann(f, 0, 2, 8, 'derecha'));
console.log('Valor exacto:', 8 / 3);

El signo de dx conserva la orientación: si b<a, la suma cambia de signo de la misma manera que la integral definida.

10 · Refinar la partición

Una tabla de errores revela la convergencia del método

Una sola aproximación no muestra cómo se comporta el algoritmo. Repetir el cálculo con n creciente permite observar si el error disminuye y con qué rapidez.

function sumaPuntoMedio(f, a, b, n) {
  const dx = (b - a) / n;
  let suma = 0;
  for (let i = 0; i < n; i += 1) {
    suma += f(a + (i + 0.5) * dx) * dx;
  }
  return suma;
}

const exacto = 2; // ∫₀^π sen(x)dx
const filas = [4, 8, 16, 32, 64, 128].map(n => {
  const aproximado = sumaPuntoMedio(Math.sin, 0, Math.PI, n);
  return { n, aproximado, error: Math.abs(aproximado - exacto) };
});
console.table(filas);

Para una función suave, el método del punto medio suele reducir el error aproximadamente por un factor de cuatro al duplicar n. La tabla permite contrastar esa expectativa con los datos.

11 · Dos caminos hacia el mismo número

El teorema fundamental conecta la suma y la primitiva

Si F′=f, podemos calcular ∫ₐᵇf(x)dx como F(b)−F(a). Una suma de Riemann aproxima el mismo valor desde la definición. Comparar ambos caminos ofrece una verificación cruzada:

sumaRiemann(f,a,b,n) ≈ F(b)−F(a)

Si no coinciden dentro del error esperado, las causas posibles incluyen:

  • La función F no es realmente una primitiva de f.
  • La suma usa puntos o anchos de subintervalo incorrectos.
  • n es demasiado pequeño para la precisión buscada.
  • El intervalo atraviesa una discontinuidad o sale del dominio.
  • El programa usa grados cuando las funciones trigonométricas esperan radianes.

12 · No evaluar a ciegas

El dominio forma parte de la especificación del programa

Una fórmula puede devolver NaN o Infinity fuera de su dominio matemático. Un verificador debe detectarlo y no convertirlo silenciosamente en un resultado válido.

function evaluarSeguro(f, x) {
  const valor = f(x);
  if (!Number.isFinite(valor)) {
    return { x, valida: false, valor: String(valor) };
  }
  return { x, valida: true, valor };
}

const logaritmo = x => Math.log(x);
const reciproca = x => 1 / x;

console.log(evaluarSeguro(logaritmo, -1));
console.log(evaluarSeguro(logaritmo, 2));
console.log(evaluarSeguro(reciproca, 0));

También hay discontinuidades que no producen NaN en los puntos muestreados. Si una partición salta sobre un polo sin evaluarlo exactamente, la suma podría parecer finita. El análisis matemático del dominio debe preceder al muestreo.

13 · Exploración interactiva

Laboratorio: derivada, rectángulos y valor exacto

Elegí una pareja f y F, cambiá el método y refiná la partición. El gráfico compara f(x) con la derivada numérica de F y dibuja los rectángulos de la suma de Riemann.

EXPERIMENTO 34

Dos verificaciones en un mismo intervalo

f(x)=x² · F(x)=x³/3 · [0,2]

Los errores de derivación e integración aparecen debajo del gráfico.
F′(x) numérica1
error de derivación0
suma de Riemann2.66204
error de integración0.00463

La derivada numérica y la suma aproximan los resultados esperados.

El panel superior superpone el integrando y la derivada numérica. El inferior representa los rectángulos y el área exacta.

Preguntas para explorar

  1. Para x², compará las sumas izquierda y derecha. ¿Qué relación tiene el signo del error con el crecimiento de la función?
  2. Duplicá n varias veces usando punto medio. ¿Cómo cambia el error?
  3. Modificá h desde 10⁻² hasta 10⁻⁸. ¿Existe un intervalo donde el error sea menor?
  4. En 1/x, ¿por qué el intervalo empieza en 1 y no en 0?

14 · Errores específicos de JavaScript

Una expresión válida puede no significar lo que parece

«Uso x ^ 2 para elevar al cuadrado»

En JavaScript, ^ es XOR a nivel de bits. La potencia se escribe x ** 2 o Math.pow(x,2).

«Paso 180 a Math.sin y espero cero»

Math.sin, Math.cos y las demás funciones trigonométricas reciben radianes. Para convertir grados: grados*Math.PI/180.

«Comparo decimales con ===»

Operaciones como 0.1+0.2 acumulan representación binaria aproximada. Usá una tolerancia justificada.

«Cuanto menor sea h, mejor»

Un paso extremo intensifica cancelación y redondeo. Probá varias escalas.

«Mi bucle recorre n+1 rectángulos»

Para n subintervalos, el índice habitual va de 0 a n−1. Incluir i=n agrega un término indebido.

«El ancho es (b−a)/(n−1)»

Si hay n subintervalos iguales, su ancho es (b−a)/n. n+1 es la cantidad de extremos de la partición.

«Ignoro NaN porque no lanzó una excepción»

Muchas operaciones inválidas devuelven NaN o Infinity. Comprobá con Number.isFinite.

15 · Comprensión y práctica

Ejercicios de comprensión

Ejercicio 1: representación polinómica

¿Qué polinomio representa el arreglo [3,−2,0,5]?

Ver solución

3−2x+5x³. La posición del coeficiente coincide con el exponente.

Ejercicio 2: derivación simbólica

Derivá el arreglo [3,−2,0,5].

Ver solución

El resultado es [−2,0,15], que representa −2+15x².

Ejercicio 3: diferencia central

Escribí la aproximación central de F′(2) con h=0,01.

Ver solución

[F(2,01)−F(1,99)]/0,02.

Ejercicio 4: elegir puntos seguros

¿Por qué no debe verificarse d[ln|x|]/dx=1/x numéricamente en x=0?

Ver solución

Ambas expresiones quedan fuera de su dominio en cero. Además, una diferencia central cruzaría la singularidad.

Ejercicio 5: ancho de partición

Calculá Δx para dividir [−1,3] en 20 subintervalos.

Ver solución

Δx=(3−(−1))/20=4/20=0,2.

Ejercicio 6: método y monotonía

Para una función positiva y creciente, ¿qué se espera de las sumas izquierda y derecha?

Ver solución

La suma izquierda subestima y la derecha sobreestima el área, porque cada rectángulo usa respectivamente la altura mínima o máxima del subintervalo.

Ejercicio 7: encontrar el operador incorrecto

Corregí const f = x => 3 * x ^ 2;.

Ver solución

const f = x => 3 * x ** 2;. El operador ^ no calcula potencias.

Ejercicio 8: alcance de la verificación

Si F′(x) y f(x) coinciden numéricamente en cien puntos, ¿queda demostrada la identidad?

Ver solución

No. Es evidencia útil y puede detectar muchos errores, pero una cantidad finita de muestras no demuestra igualdad en todo un intervalo.

16 · Síntesis

Ideas para recordar

  • La verificación computacional complementa el razonamiento matemático; no lo reemplaza.
  • Una función puede representarse como código evaluable o como una estructura simbólica limitada.
  • Los coeficientes permiten derivar e integrar polinomios exactamente.
  • La diferencia central aproxima derivadas generales y depende de una elección razonable de h.
  • Los números de punto flotante se comparan con tolerancias absolutas y relativas.
  • Una suma de Riemann necesita n subintervalos, ancho (b−a)/n y una regla clara de muestreo.
  • Refinar la partición y registrar errores permite estudiar convergencia, no solo obtener una cifra.
  • Dominio, discontinuidades, radianes y operadores del lenguaje deben revisarse explícitamente.
  • Derivada, regla de Barrow y suma de Riemann ofrecen verificaciones cruzadas del mismo problema.