Fundamentos · Tema 07

Tolerancias y criterios de parada

Cómo decidir cuándo una aproximación es suficientemente buena, detectar fallos y finalizar un algoritmo iterativo de manera segura.

01 · Punto de partida

Un método iterativo necesita saber cuándo terminar

Los métodos numéricos suelen construir una secuencia de aproximaciones. Detenerse demasiado pronto produce un resultado impreciso; continuar innecesariamente consume recursos y puede llegar al límite de la aritmética de punto flotante.

Un ciclo escrito así no contiene una decisión numérica:

while (true) {
  aproximacion = mejorar(aproximacion);
}

Necesitamos convertir la idea “suficientemente bueno” en condiciones medibles. Un diseño robusto responde cuatro preguntas:

  • ¿Qué cantidad utilizaremos para estimar la calidad?
  • ¿Qué umbral resulta apropiado para la escala del problema?
  • ¿Qué límites impiden una ejecución interminable?
  • ¿Cómo informaremos el motivo de finalización?

02 · Definir lo aceptable

¿Qué es una tolerancia?

Una tolerancia es un límite previamente elegido para una medida de error, residuo o cambio. Si la medida queda por debajo del límite, aceptamos la aproximación según ese criterio.

medida ≤ tolerancia

La tolerancia no es una propiedad universal del algoritmo. Depende de:

m, s, €

Unidades

Una tolerancia absoluta debe expresarse en las mismas unidades que la cantidad evaluada.

10ᵏ

Escala

Una diferencia aceptable cerca de 1 puede resultar absurda cerca de 10⁹.

CPU

Costo

Exigir más precisión suele requerir más iteraciones, evaluaciones o memoria.

También depende de la precisión de los datos. No tiene sentido exigir un error de 10⁻¹² a un modelo construido con mediciones que solo distinguen centésimas.

03 · Dos escalas complementarias

Tolerancia absoluta y relativa

Una tolerancia absoluta controla una distancia fija:

|a − b| ≤ tolabs

Funciona bien cerca de cero, pero no se adapta a magnitudes muy diferentes. Una tolerancia relativa escala con el tamaño de los valores:

|a − b| ≤ tolrel × max(|a|, |b|)

Cerca de cero, la escala relativa también se aproxima a cero y puede exigir una igualdad imposible. Por eso suelen combinarse:

|a − b| ≤ tolabs + tolrel × max(|a|, |b|)
function cerca(a, b, toleranciaAbsoluta = 1e-12,
               toleranciaRelativa = 1e-9) {
  if (a === b) return true;
  if (!Number.isFinite(a) || !Number.isFinite(b)) return false;

  const limite = toleranciaAbsoluta
    + toleranciaRelativa * Math.max(Math.abs(a), Math.abs(b));
  return Math.abs(a - b) <= limite;
}

console.log(cerca(0, 1e-13));
console.log(cerca(1e9, 1e9 + 0.1));

También puede usarse el máximo de ambas tolerancias en lugar de la suma. Las dos políticas son válidas si se documentan y se eligen coherentemente.

04 · La medida ideal

Error verdadero

Si conocemos la solución exacta x*, el criterio más directo es:

|xn − x*| ≤ tol

Este criterio sirve para estudiar y probar un método, pero rara vez está disponible en producción: si conociéramos x*, probablemente no necesitaríamos aproximarlo.

Aun así, los problemas de prueba con solución conocida son importantes para:

  • verificar una implementación;
  • medir experimentalmente el orden de convergencia;
  • comparar criterios estimados con el error real;
  • calibrar tolerancias y límites de iteración.

05 · Estabilidad entre iteraciones

Cambio entre aproximaciones sucesivas

Una medida accesible es la diferencia entre las dos últimas aproximaciones:

Δn = |xn − xn−1|

Podemos aplicar una tolerancia combinada:

Δn ≤ tolabs + tolrel × |xn|
function cambioAceptable(anterior, actual, tolAbs, tolRel) {
  const cambio = Math.abs(actual - anterior);
  const limite = tolAbs + tolRel * Math.abs(actual);
  return { aceptado: cambio <= limite, cambio, limite };
}

console.log(cambioAceptable(1.41421356, 1.414213562, 1e-12, 1e-8));

Un cambio pequeño sugiere que la sucesión se estabiliza, pero no garantiza que esté cerca de la solución. Puede existir convergencia lenta, estancamiento de punto flotante o un punto fijo que no resuelve el problema original.

06 · Cumplimiento de la ecuación

Residuo

Al resolver f(x) = 0, el residuo es:

rn = |f(xn)|

Un criterio posible es rₙ ≤ tolResiduo. Tiene la ventaja de comprobar directamente la ecuación, pero debe interpretarse según su escala y condicionamiento.

Función empinada

Residuo grande cerca de la raíz

Una pendiente elevada transforma un pequeño error en x en un residuo mayor.

Función plana

Residuo pequeño lejos de la raíz

Una pendiente diminuta puede ocultar un error considerable en x.

Cerca de una raíz simple x*, una aproximación de primer orden relaciona ambas medidas:

|xn − x*| ≈ |f(xn)| / |f′(x*)|

Por eso, el residuo debe combinarse con información de sensibilidad o con otro criterio.

07 · Garantías del método

Cotas de error e intervalos

Algunos métodos proporcionan una cota teórica. En bisección, si comenzamos con un intervalo de longitud L = b−a, después de n divisiones la longitud es:

Ln = (b − a) / 2n

El punto medio está como máximo a la mitad de esa longitud de la raíz encerrada. Podemos elegir anticipadamente la cantidad de iteraciones:

n ≥ ⌈log₂((b − a) / anchoObjetivo)⌉
function iteracionesBiseccion(inicio, fin, anchoObjetivo) {
  if (!(fin > inicio) || !(anchoObjetivo > 0)) {
    throw new Error("Intervalo o ancho objetivo inválido");
  }
  return Math.max(
    0,
    Math.ceil(Math.log2((fin - inicio) / anchoObjetivo))
  );
}

console.log(iteracionesBiseccion(0, 2, 1e-8));

Una cota demostrada ofrece más seguridad que observar únicamente cambios sucesivos. Cada método del curso tendrá sus propias estimaciones y condiciones.

08 · Redes de seguridad

Máximo de iteraciones, tiempo y evaluaciones

Todo algoritmo iterativo debería tener al menos un límite independiente de la convergencia. Las opciones más frecuentes son:

N

Iteraciones

Detenerse después de una cantidad máxima de actualizaciones.

f()

Evaluaciones

Limitar llamadas costosas a la función o al modelo.

ms

Tiempo

Respetar un presupuesto temporal en aplicaciones interactivas o servicios.

Alcanzar un límite no equivale a converger. El algoritmo debe devolver un estado que permita distinguir una solución aceptada de una finalización por presupuesto agotado.

const resultado = {
  valor: aproximacion,
  convergio: false,
  motivo: "maximo_iteraciones",
  iteraciones: 100,
  residuo: 2.7e-6
};

09 · Límite de la representación

Detectar estancamiento y ciclos

Puede llegar un momento en que la actualización calculada sea demasiado pequeña para modificar el Number almacenado:

xn+1 === xn

Esto indica estancamiento numérico, no necesariamente éxito. Debemos comprobar el residuo u otra medida antes de declarar convergencia.

También pueden aparecer ciclos cortos, por ejemplo a → b → a → b. Guardar las últimas aproximaciones permite detectar algunos casos.

function estadoActual(anterior, actual, haceDos, residuo, tolerancia) {
  if (residuo <= tolerancia) return "convergencia";
  if (actual === anterior) return "estancamiento";
  if (actual === haceDos) return "ciclo_de_periodo_2";
  return "continuar";
}

10 · Decisiones robustas

Combinar criterios

Un solucionador puede observar simultáneamente cambio, residuo, cota e iteraciones. La forma de combinarlos expresa una política:

Ejemplos de combinaciones lógicas.
PolíticaCondiciónConsecuencia
PermisivaCambio pequeño o residuo pequeñoPuede detenerse antes, con menos garantías
ConservadoraCambio pequeño y residuo pequeñoExige evidencia de ambos tipos
Con cotaCota teórica menor que toleranciaUtiliza la garantía específica del método
SeguridadMáximo alcanzado o valor no finitoFinaliza sin declarar convergencia

No existe una combinación universal. Para una raíz, puede ser razonable exigir residuo y cambio pequeños. Para bisección, el ancho del intervalo ofrece una garantía directa. Para una simulación en tiempo real, el presupuesto temporal puede dominar.

11 · Patrón de implementación

Un ciclo iterativo robusto

El siguiente patrón separa actualización, evaluación y finalización:

function resolverIterativamente({
  inicial,
  actualizar,
  residual,
  toleranciaAbsoluta = 1e-12,
  toleranciaRelativa = 1e-9,
  toleranciaResiduo = 1e-10,
  maxIteraciones = 100
}) {
  let anterior = inicial;

  for (let iteracion = 1; iteracion <= maxIteraciones; iteracion++) {
    const actual = actualizar(anterior);
    const residuo = Math.abs(residual(actual));

    if (!Number.isFinite(actual) || !Number.isFinite(residuo)) {
      return { valor: actual, convergio: false,
        motivo: "valor_no_finito", iteracion, residuo };
    }

    const cambio = Math.abs(actual - anterior);
    const limiteCambio = toleranciaAbsoluta
      + toleranciaRelativa * Math.abs(actual);

    if (cambio <= limiteCambio && residuo <= toleranciaResiduo) {
      return { valor: actual, convergio: true,
        motivo: "tolerancias", iteracion, cambio, residuo };
    }
    if (actual === anterior) {
      return { valor: actual, convergio: false,
        motivo: "estancamiento", iteracion, cambio, residuo };
    }
    anterior = actual;
  }

  return { valor: anterior, convergio: false,
    motivo: "maximo_iteraciones", iteracion: maxIteraciones };
}

La función no oculta los fallos: devuelve un diagnóstico estructurado para que la aplicación decida si reintenta, cambia de método o informa al usuario.

12 · Aplicación

Aproximar una raíz cuadrada

Para aproximar √S utilizamos la actualización babilónica:

xn+1 = ½(xn + S/xn)

El residuo de la ecuación x² − S = 0 es |x² − S|. Podemos aplicar el patrón anterior:

const numero = 2;

const resultado = resolverIterativamente({
  inicial: 1,
  actualizar: x => (x + numero / x) / 2,
  residual: x => x * x - numero,
  toleranciaAbsoluta: 1e-12,
  toleranciaRelativa: 1e-10,
  toleranciaResiduo: 1e-12,
  maxIteraciones: 50
});

console.log(resultado);

La tolerancia del cambio está expresada en unidades de x; la del residuo, en unidades de x². Aunque ambas tengan valores numéricos parecidos, representan cantidades distintas.

13 · Exploración interactiva

Laboratorio: comparar criterios de parada

Aproximaremos √2 y podremos detenernos por cambio, residuo o ambos. Variá la tolerancia y el máximo de iteraciones para observar el motivo de finalización.

EXPERIMENTO 07

¿Cuándo detener la iteración?

tolerancia = 10⁻⁸

Los resultados numéricos aparecen debajo.
Aproximación1,414213562
Iteraciones5
Residuo final4,44e−16
MotivoCambio y residuo

El método alcanzó las condiciones solicitadas.

Preguntas para explorar

  1. Reducí el máximo a dos iteraciones. ¿Cómo informa el laboratorio la salida?
  2. ¿Cuántas iteraciones adicionales exige pasar de 10⁻⁴ a 10⁻¹²?
  3. Compará “cambio y residuo” con “cambio o residuo”.
  4. Probá 10⁻¹⁵. ¿Aparece alguna limitación de punto flotante?

14 · Diseño de interfaces

Informar más que un número

Una API numérica debería devolver suficiente información para auditar la decisión:

Campos útiles de un resultado iterativo.
CampoPropósito
valorMejor aproximación disponible.
convergioDistingue éxito numérico de finalización forzada.
motivoTolerancia, cota, estancamiento, límite o valor inválido.
iteracionesCosto y diagnóstico de convergencia.
cambioDiferencia entre las últimas aproximaciones.
residuoCumplimiento de la ecuación original.
historialOpcional para gráficos, depuración y análisis.

Es preferible devolver el mejor valor junto con una advertencia que devolver null sin contexto. La aplicación puede decidir si el resultado parcial es útil.

15 · Comprensión

Confusiones frecuentes

«Una tolerancia pequeña siempre mejora el resultado»

Puede aumentar el costo sin aportar precisión si los datos, el condicionamiento o el punto flotante ya establecen un límite.

«Residuo pequeño significa error pequeño»

La relación depende de la sensibilidad del problema. Una función plana puede tener residuo pequeño lejos de la raíz.

«Si actual === anterior, el método convergió»

La igualdad puede significar estancamiento. Debe comprobarse el residuo, una cota u otra condición.

«Máximo de iteraciones es un criterio de convergencia»

Es una medida de seguridad o presupuesto. Alcanzarlo no permite declarar que la aproximación satisface la precisión.

«La misma tolerancia sirve para cualquier unidad»

Una tolerancia absoluta de 0.01 tiene significados distintos en metros, segundos o dólares. Debe vincularse al dominio.

16 · Práctica guiada

Ejercicios

Ejercicio 1: tolerancia combinada

Para a = 1 000 000, b = 1 000 000.005, tolAbs = 0.001 y tolRel = 10⁻⁸, determiná si cumplen |a−b| ≤ tolAbs + tolRel·max(|a|,|b|).

Ver solución

La diferencia es aproximadamente 0.005. El límite es 0.001 + 0.01 = 0.011 aproximadamente. Por lo tanto, los valores se aceptan según esta política.

Ejercicio 2: iteraciones de bisección

¿Cuántas divisiones se necesitan para reducir un intervalo de longitud 4 a un ancho máximo de 10⁻⁶?

Ver solución

n ≥ ceil(log₂(4/10⁻⁶)) = ceil(log₂(4 000 000)) = 22. Después de 22 divisiones, el ancho es menor o igual que el solicitado.

Ejercicio 3: elegir criterios

Para encontrar una raíz de f(x)=0, proponé una política que combine cambio, residuo y máximo de iteraciones.

Ver una posible respuesta

Declarar convergencia cuando el cambio satisfaga tolerancias absoluta y relativa y el residuo esté por debajo de su tolerancia. Detener sin declarar convergencia al alcanzar el máximo, obtener un valor no finito o detectar estancamiento con residuo inaceptable.

Ejercicio 4: detectar un fallo

Un algoritmo devuelve el mismo valor en dos iteraciones, pero el residuo es 0.4 y la tolerancia de residuo es 10⁻⁸. ¿Qué estado debería informar?

Ver solución

Debe informar estancamiento sin convergencia. La igualdad entre iteraciones no compensa el residuo inaceptable.

Ejercicio 5: implementar un resultado

Escribí una función que construya un objeto de resultado uniforme para convergencia, máximo de iteraciones o valor no finito.

Ver una posible solución
function crearResultado(valor, iteraciones, motivo, diagnostico = {}) {
  const motivosExitosos = new Set(["tolerancia", "cota"]);
  return {
    valor,
    iteraciones,
    motivo,
    convergio: motivosExitosos.has(motivo),
    ...diagnostico
  };
}

console.log(crearResultado(1.4142, 6, "tolerancia", {
  cambio: 2e-10,
  residuo: 3e-12
}));

17 · Síntesis

Ideas para recordar

  • Una tolerancia convierte “suficientemente bueno” en una condición medible.
  • Las tolerancias absolutas funcionan cerca de cero; las relativas se adaptan a la escala.
  • El cambio entre iteraciones, el residuo y las cotas miden aspectos diferentes.
  • Ningún criterio observable garantiza por sí solo un error verdadero pequeño.
  • Todo ciclo iterativo necesita un límite de seguridad independiente de la convergencia.
  • Estancamiento e igualdad entre iteraciones no son sinónimos de éxito.
  • Combinar criterios aumenta la robustez cuando sus escalas están bien definidas.
  • El resultado debe incluir valor, estado, motivo, iteraciones y diagnósticos.

En el próximo tema comenzaremos la unidad de raíces de ecuaciones no lineales: cómo formular f(x)=0, localizar intervalos candidatos y visualizar las soluciones.