01 · Punto de partida
Los errores no permanecen aislados
Los datos de entrada pueden contener error de medición, los números se almacenan con precisión finita y cada operación puede redondear su resultado. Cuando una salida se utiliza como entrada del paso siguiente, esas pequeñas diferencias recorren el algoritmo.
Consideremos dos mediciones: a = 100.0 ± 0.1 y b = 99.9 ± 0.1. La diferencia calculada es a − b = 0.1. Sin embargo, los valores verdaderos compatibles con las mediciones permiten diferencias desde −0.1 hasta 0.3. El resultado es pequeño, pero su incertidumbre no lo es.
Para diseñar métodos confiables necesitamos responder:
- ¿Cómo cambia el error al sumar, restar, multiplicar o dividir?
- ¿Qué operaciones eliminan cifras significativas?
- ¿Podemos escribir una fórmula equivalente que se comporte mejor?
- ¿Cómo acumulamos muchos valores sin perder aportes pequeños?
02 · Representar una perturbación
Valor verdadero, aproximación y error
Podemos representar una entrada aproximada como el valor verdadero más una perturbación:
El símbolo Δx describe aquí un error con signo. Si una función recibe x̃ en lugar de x, la salida cambia:
El objetivo de la propagación de errores es relacionar Δf con los errores de entrada. Algunas operaciones permiten obtener cotas sencillas; en otras utilizaremos aproximaciones locales.
- Error de entrada
- Incertidumbre o aproximación presente antes de ejecutar el cálculo.
- Error propagado
- Parte del error de salida causada por las entradas inexactas.
- Error de cálculo
- Error adicional introducido por truncamiento, redondeo e implementación.
- Error total
- Efecto combinado de todas las fuentes sobre el resultado final.
03 · Operaciones aditivas
Propagación en sumas y restas
Sean x̃ = x + Δx e ỹ = y + Δy. Al sumar:
Y al restar:
Si solo conocemos cotas absolutas |Δx| ≤ εx y |Δy| ≤ εy, una cota segura para ambas operaciones es:
Ejemplo con intervalos
Si x = 20.0 ± 0.2 e y = 5.0 ± 0.1, entonces:
x + y = 25.0 ± 0.3como cota conservadora;x − y = 15.0 ± 0.3como cota conservadora.
La cota suma los peores casos. Si los errores son aleatorios e independientes pueden utilizarse modelos estadísticos menos conservadores, pero eso requiere supuestos adicionales.
04 · Operaciones multiplicativas
Propagación en productos y cocientes
Para errores pequeños, los errores relativos de un producto se combinan aproximadamente mediante una suma:
En un cociente ocurre algo similar, siempre que el denominador no sea cero ni esté demasiado cerca de cero:
La suma ofrece una cota aproximada de peor caso. Si x = 10 ± 1 % e y = 4 ± 2 %, el producto 40 puede tener aproximadamente hasta un 3 % de error relativo.
| Operación | Medida útil | Regla aproximada o cota |
|---|---|---|
x ± y | Error absoluto | Ea ≤ Ea(x) + Ea(y) |
x × y | Error relativo | Er ≈ Er(x) + Er(y) |
x / y | Error relativo | Er ≈ Er(x) + Er(y) |
xⁿ | Error relativo | Er(xⁿ) ≈ |n| Er(x) |
05 · Sensibilidad local
Propagación a través de una función
Si f es derivable y Δx es pequeño, la derivada aproxima el cambio de salida:
En magnitud:
Una derivada grande indica que una pequeña perturbación de entrada puede producir una diferencia de salida considerable.
Ejemplo: área de un círculo
Para A(r) = πr², la derivada es A′(r) = 2πr. Si medimos r = 10 cm con un error máximo de 0.01 cm:
function estimarErrorSalida(derivada, x, errorEntrada) {
return Math.abs(derivada(x)) * Math.abs(errorEntrada);
}
const derivadaArea = radio => 2 * Math.PI * radio;
console.log(estimarErrorSalida(derivadaArea, 10, 0.01));
En el tema siguiente distinguiremos formalmente la sensibilidad propia del problema de la estabilidad del algoritmo que utilizamos para resolverlo.
06 · Pérdida de cifras
Cancelación al restar números cercanos
La cancelación ocurre al restar dos números casi iguales. Sus primeras cifras coinciden y desaparecen, dejando un resultado que depende de las últimas cifras, precisamente las menos confiables.
Supongamos que almacenamos cuatro cifras significativas:
Si ambos valores tenían errores de apenas ±0.0005, el error de la diferencia puede ser del mismo orden que el resultado. El error absoluto no necesariamente aumentó, pero el error relativo puede volverse enorme porque la salida es muy pequeña.
const a = 1.000000000000001;
const b = 1.000000000000000;
const diferencia = a - b;
console.log(diferencia);
console.log(diferencia.toPrecision(17));
07 · Reformulación algebraica
Evitar una resta peligrosa
Para x grande, la expresión siguiente resta dos raíces casi iguales:
Multiplicando por el conjugado obtenemos una forma algebraicamente equivalente:
La segunda forma reemplaza la resta de números cercanos por una suma y una división.
function diferenciaDirecta(x) {
return Math.sqrt(x + 1) - Math.sqrt(x);
}
function diferenciaEstable(x) {
return 1 / (Math.sqrt(x + 1) + Math.sqrt(x));
}
for (const x of [1, 1e8, 1e12, 1e16]) {
console.log(x, {
directa: diferenciaDirecta(x),
estable: diferenciaEstable(x)
});
}
Para x = 10¹⁶, x + 1 se representa como el mismo Number que x. La forma directa devuelve cero; la reformulada conserva un resultado cercano a 5×10⁻⁹.
08 · Caso clásico
Fórmula cuadrática estable
La fórmula habitual para las raíces de ax² + bx + c = 0 es:
Si b² es mucho mayor que 4ac, una de las ramas resta cantidades casi iguales. Podemos calcular primero:
Y obtener las raíces mediante x₁ = q/a y x₂ = c/q. Así evitamos la resta peligrosa.
function raicesCuadraticasEstables(a, b, c) {
const discriminante = b * b - 4 * a * c;
if (discriminante < 0) return [];
const raizDiscriminante = Math.sqrt(discriminante);
const signoB = b >= 0 ? 1 : -1;
const q = -0.5 * (b + signoB * raizDiscriminante);
if (q === 0) return [0, 0];
return [q / a, c / q];
}
console.log(raicesCuadraticasEstables(1, 1e8, 1));
El método devuelve una raíz cercana a −10⁸ y otra cercana a −10⁻⁸. La fórmula directa puede perder la raíz pequeña por cancelación.
09 · Acumular muchos valores
Orden de suma y escala
Cuando sumamos una cantidad pequeña a otra mucho mayor, el aporte puede quedar por debajo de la separación entre números representables:
console.log(1e16 + 1 === 1e16); // true
const a = (1e16 + -1e16) + 1;
const b = 1e16 + (-1e16 + 1);
console.log(a); // 1
console.log(b); // 0
La suma matemática es asociativa; la suma de punto flotante no lo es. Cuando todos los valores tienen el mismo signo, sumar primero los de menor magnitud suele conservar más información. Si hay signos diferentes, el problema es más complejo porque también puede aparecer cancelación.
Ordenar tiene un costo y no resuelve todos los casos. Para acumulaciones importantes existen algoritmos especializados.
10 · Suma compensada
Algoritmo de Kahan
La suma compensada de Kahan mantiene una variable adicional que intenta recuperar las partes pequeñas perdidas en cada operación.
function sumaKahan(valores) {
let suma = 0;
let compensacion = 0;
for (const valor of valores) {
const ajustado = valor - compensacion;
const siguiente = suma + ajustado;
compensacion = (siguiente - suma) - ajustado;
suma = siguiente;
}
return suma;
}
const datos = Array(100_000).fill(0.1);
const sumaComun = datos.reduce((total, valor) => total + valor, 0);
const sumaCompensada = sumaKahan(datos);
console.log({ sumaComun, sumaCompensada, esperado: 10_000 });
Kahan mejora notablemente muchas acumulaciones con un costo pequeño, pero no es una solución universal. Variantes como Neumaier manejan mejor algunos órdenes con valores de signos y magnitudes muy diferentes.
11 · Extremos del rango
Desbordamiento, subdesbordamiento y escalado
Un resultado intermedio puede salir del rango representable aunque el resultado final sea finito. Por ejemplo, calcular directamente √(x² + y²) puede desbordar al elevar números grandes al cuadrado o perder los pequeños por subdesbordamiento.
const x = 1e200;
const y = 1e200;
console.log(Math.sqrt(x * x + y * y)); // Infinity
console.log(Math.hypot(x, y)); // aproximadamente 1.414e200
Una versión escalada divide primero por la mayor magnitud:
Math.hypot utiliza estrategias estables de este tipo. Escalar variables es una herramienta general para mantener los intermedios dentro de un rango seguro.
12 · Diseño numérico
Estrategias para controlar la propagación
Reformular
Buscar expresiones equivalentes que eviten restas peligrosas y extremos intermedios.
Escalar
Normalizar magnitudes para trabajar en una región numérica segura.
Compensar
Utilizar algoritmos de suma que registren información perdida.
Validar
Comparar formas equivalentes, mayor precisión o soluciones conocidas.
Registrar
Observar magnitudes intermedias, residuos y advertencias numéricas.
Acotar
Propagar intervalos o cotas cuando la incertidumbre de entrada es conocida.
La estrategia comienza por reconocer dónde se pierde información. Agregar más decimales a la salida no corrige un algoritmo que ya canceló las cifras útiles.
13 · Exploración interactiva
Laboratorio: observar la cancelación
El experimento evalúa √(x + 1) − √x en forma directa y racionalizada para x = 10ᵉ. El gráfico muestra el error relativo de la forma directa respecto de la estable.
Resta de raíces cercanas
x = 10⁰ = 1
Para esta magnitud, ambas formas producen resultados muy cercanos.
Preguntas para explorar
- ¿A partir de qué exponente comienza a crecer visiblemente el error?
- ¿En qué momento
x + 1se representa igual quex? - ¿Por qué la forma estable puede devolver un valor distinto de cero en ese caso?
- ¿La expresión matemática cambió al racionalizar?
14 · Comprobar una implementación
Diagnóstico de problemas numéricos
Cuando un resultado parece incorrecto o cambia inesperadamente, conviene seguir un procedimiento:
- 1Inspeccionar escalas.
Buscar entradas e intermedios que difieran por muchos órdenes de magnitud.
- 2Localizar restas.
Identificar sustracciones de valores cercanos y divisiones por cantidades pequeñas.
- 3Comparar formulaciones.
Evaluar una expresión algebraicamente equivalente o un algoritmo alternativo.
- 4Aumentar la precisión de referencia.
Utilizar una biblioteca multiprecisión para diagnosticar, aunque la producción use
Number. - 5Probar casos límite.
Incluir valores casi iguales, muy grandes, muy pequeños y combinaciones de signos.
function compararFormas(x) {
const directa = Math.sqrt(x + 1) - Math.sqrt(x);
const estable = 1 / (Math.sqrt(x + 1) + Math.sqrt(x));
const diferencia = Math.abs(directa - estable);
return {
x,
directa,
estable,
diferencia,
incrementoPerdido: x + 1 === x
};
}
console.table([1, 1e8, 1e12, 1e16].map(compararFormas));
15 · Comprensión
Confusiones frecuentes
«La resta siempre aumenta el error absoluto»
No necesariamente. El problema típico es que el resultado se vuelve pequeño mientras el error absoluto permanece, por lo que el error relativo aumenta.
«Expresiones equivalentes deben producir los mismos bits»
La equivalencia algebraica supone aritmética exacta. En punto flotante, los resultados intermedios se redondean y el orden de operaciones importa.
«Usar Number.EPSILON evita la cancelación»
Agregar una constante no recupera cifras perdidas y puede modificar el problema. La solución suele ser reformular o utilizar mayor precisión.
«Kahan vuelve exacta cualquier suma»
Reduce el error en muchas acumulaciones, pero sigue trabajando con precisión finita y tiene casos difíciles. Es una mejora algorítmica, no aritmética exacta.
«Infinity solo aparece cuando el resultado final es enorme»
También puede aparecer en un intermedio, como x*x, aunque una forma escalada del resultado final sea finita.
16 · Práctica guiada
Ejercicios
Ejercicio 1: suma con incertidumbre
Dos longitudes son 12.0 ± 0.1 cm y 8.0 ± 0.2 cm. Calculá una cota conservadora para el error absoluto de la suma y de la diferencia.
Ver solución
En ambos casos la cota es 0.1 + 0.2 = 0.3 cm. Podemos informar 20.0 ± 0.3 cm y 4.0 ± 0.3 cm. La diferencia tiene un error relativo mayor porque su valor es menor.
Ejercicio 2: producto
El largo de un rectángulo tiene un error relativo máximo de 1 % y el ancho uno de 2 %. Estimá el error relativo máximo de primer orden para el área.
Ver solución
Como el área es un producto, la cota relativa aproximada es 1 % + 2 % = 3 %.
Ejercicio 3: identificar cancelación
¿Cuál de estas expresiones es más vulnerable cuando x es pequeño: cos(x) − 1 o cos(x) + 1? Justificá.
Ver solución razonada
Cuando x es pequeño, cos(x) está cerca de 1. La expresión cos(x) − 1 resta números cercanos y puede perder cifras significativas. Una reformulación útil es −2 sin²(x/2).
Ejercicio 4: reformular
Implementá las dos formas de cos(x) − 1 y comparalas para x = 10⁻⁴, 10⁻⁸ y 10⁻¹².
Ver una posible solución
function cosenoMenosUnoDirecto(x) {
return Math.cos(x) - 1;
}
function cosenoMenosUnoEstable(x) {
return -2 * Math.sin(x / 2) ** 2;
}
for (const x of [1e-4, 1e-8, 1e-12]) {
console.log(x, {
directo: cosenoMenosUnoDirecto(x),
estable: cosenoMenosUnoEstable(x)
});
}
Ejercicio 5: suma precisa
Compará la suma común y la suma de Kahan para cien mil copias de 0.01. Medí el error absoluto respecto de 1000.
Ver una posible solución
const valores = Array(100_000).fill(0.01);
const comun = valores.reduce((suma, x) => suma + x, 0);
const compensada = sumaKahan(valores);
console.log({
errorComun: Math.abs(comun - 1000),
errorCompensado: Math.abs(compensada - 1000)
});
17 · Síntesis
Ideas para recordar
- Los errores de entrada y de cálculo se propagan a través de cada operación.
- En sumas y restas se combinan naturalmente errores absolutos; en productos y cocientes, errores relativos.
- La derivada aproxima cuánto amplifica una función una perturbación pequeña.
- Restar números cercanos puede destruir cifras significativas y aumentar el error relativo.
- Una reformulación algebraica puede evitar cancelación sin cambiar el problema matemático.
- El orden de suma importa en punto flotante y una suma compensada puede conservar aportes pequeños.
- Escalar evita desbordamientos o subdesbordamientos innecesarios en resultados intermedios.
- La estabilidad debe comprobarse con casos extremos y formulaciones de referencia.
En el próximo tema diferenciaremos condicionamiento, estabilidad y convergencia: tres conceptos relacionados, pero correspondientes al problema, al algoritmo y a la sucesión de aproximaciones.