01 · Dos modelos
La suma real y la suma de la máquina
En aritmética real, una suma finita puede reagruparse y reordenarse sin cambiar su valor. En una computadora, la mayoría de los números reales se reemplazan por aproximaciones y cada operación vuelve a redondear el resultado.
Si fl(x) representa el valor almacenado de x, el cálculo efectivo es una secuencia como:
El redondeo intermedio modifica la entrada de la operación siguiente. Por eso importan tanto el orden como el algoritmo de acumulación.
02 · Representación
Qué almacena un Number de JavaScript
El tipo Number utiliza normalmente el formato binario de doble precisión IEEE 754. Un valor finito se representa mediante signo, exponente y una significación de 53 bits de precisión efectiva.
Esto permite un rango enorme, pero solo alrededor de 16 cifras decimales significativas. Números como 0.1 no tienen representación binaria finita:
console.log({
suma: 0.1 + 0.2,
igualdadExacta: 0.1 + 0.2 === 0.3,
epsilon: Number.EPSILON,
enteroSeguroMaximo: Number.MAX_SAFE_INTEGER
});El resultado no indica un fallo del lenguaje: es la consecuencia esperada de representar una recta continua con una cantidad finita de patrones binarios.
03 · Precisión relativa
La distancia entre números cambia con la escala
Number.EPSILON=2⁻⁵² es la separación entre 1 y el siguiente número representable mayor que 1. No es una tolerancia universal.
Cerca de una magnitud |x|, el espaciado es aproximadamente proporcional a:
Alrededor de 10¹⁶, la separación ya es del orden de unidades. Entonces sumar 1 puede no alterar el acumulador:
La precisión es relativa a la escala, no una cantidad fija de decimales después de la coma.
04 · Propiedad perdida
La suma en coma flotante no es asociativa
const a = 1e16;
const b = -1e16;
const c = 1;
console.log({
izquierda: (a + b) + c,
derecha: a + (b + c),
exacto: 1
});En el primer orden, a+b se cancela exactamente y queda 1. En el segundo, b+c se redondea a b; luego a+b produce 0.
Ambas expresiones son idénticas en los reales, pero describen secuencias distintas de redondeos.
05 · Pérdida de cifras
Cancelación y condicionamiento
Restar dos cantidades cercanas puede eliminar sus cifras principales y dejar expuestos los errores presentes en las cifras menores. Este fenómeno se denomina cancelación sustractiva.
Hay que distinguir dos cuestiones:
- Problema mal condicionado
- Pequeños cambios en los datos exactos causan grandes cambios relativos en el resultado.
- Algoritmo inestable
- El procedimiento introduce o amplifica más error del necesario para ese problema.
Ningún algoritmo de suma puede recuperar información que ya se perdió al construir los datos, pero sí puede evitar perder información adicional durante la acumulación.
06 · Método básico
La acumulación de izquierda a derecha
function sumaIngenua(valores) {
let suma = 0;
for (const valor of valores) suma += valor;
return suma;
}
const datos = [1e16, 1, 1, 1, -1e16];
console.log({ ingenua: sumaIngenua(datos), exacta: 3 });Este algoritmo usa tiempo lineal, memoria constante y suele ser suficiente cuando los términos tienen escalas similares y no existe una cancelación extrema.
Su error depende del orden. En el peor caso, los redondeos de muchas operaciones pueden acumularse aproximadamente en proporción a la cantidad de sumandos.
07 · Estrategia simple
Sumar primero las magnitudes pequeñas
Para términos no negativos, ordenar por valor absoluto creciente suele mejorar la precisión. Los términos pequeños se combinan entre sí antes de enfrentarse a un acumulador grande que podría absorberlos.
Sin embargo, ordenar cuesta aproximadamente O(n log n), modifica el orden original y no constituye una solución universal cuando hay signos y cancelaciones.
08 · Árbol de reducción
Sumación por pares
En lugar de formar una cadena larga, la suma por pares combina valores en un árbol equilibrado. Cada resultado atraviesa solo unas log₂n etapas de redondeo.
El trabajo total sigue siendo O(n), mientras que la profundidad se reduce de n a O(log n). Además, la estructura se presta a procesamiento paralelo.
function sumaPorPares(valores) {
if (valores.length === 0) return 0;
let nivel = valores.slice();
while (nivel.length > 1) {
const siguiente = [];
for (let i = 0; i < nivel.length; i += 2) {
siguiente.push(i + 1 < nivel.length
? nivel[i] + nivel[i + 1]
: nivel[i]);
}
nivel = siguiente;
}
return nivel[0];
}09 · Suma compensada
El algoritmo de Kahan
Kahan mantiene una compensación c que aproxima los bits de baja magnitud perdidos en la suma anterior. Antes de agregar el término siguiente, devuelve esa corrección al cálculo.
function sumaKahan(valores) {
let suma = 0;
let compensacion = 0;
for (const valor of valores) {
const corregido = valor - compensacion;
const siguiente = suma + corregido;
compensacion = (siguiente - suma) - corregido;
suma = siguiente;
}
return suma;
}La resta final reconstruye el error local de redondeo bajo el modelo habitual. El costo es unas pocas operaciones adicionales por término y memoria constante.
10 · Interpretación
Qué representa la compensación
Si suma es tan grande que una parte de corregido desaparece al calcular siguiente, entonces:
estima esa diferencia. En la iteración posterior se resta la compensación —que posee el signo adecuado— del nuevo valor.
La compensación no es una «memoria exacta» de todo el error ni garantiza el resultado correctamente redondeado en cualquier secuencia. Es una corrección eficaz bajo condiciones comunes y mejora drásticamente muchas sumas de términos pequeños sobre un acumulador grande.
11 · Compensación reforzada
La variante de Neumaier
Kahan puede comportarse mal cuando el próximo sumando tiene mayor magnitud que el acumulador. Neumaier decide qué operando domina y acumula explícitamente la parte pequeña.
function sumaNeumaier(valores) {
let suma = 0;
let compensacion = 0;
for (const valor of valores) {
const siguiente = suma + valor;
if (Math.abs(suma) >= Math.abs(valor)) {
compensacion += (suma - siguiente) + valor;
} else {
compensacion += (valor - siguiente) + suma;
}
suma = siguiente;
}
return suma + compensacion;
}La suma final incorpora la corrección acumulada. Sigue usando tiempo lineal y memoria constante, a cambio de más operaciones y una comparación por elemento.
12 · Elección práctica
Costos y fortalezas
| Método | Tiempo | Memoria extra | Uso característico |
|---|---|---|---|
| Ingenuo | O(n) | O(1) | Datos benignos o baja exigencia |
| Ordenado por magnitud | O(n log n) | Depende del ordenamiento | Términos no negativos con gran rango |
| Por pares | O(n) | O(n) en la versión simple | Reducciones grandes o paralelas |
| Kahan | O(n) | O(1) | Flujos secuenciales con incrementos pequeños |
| Neumaier | O(n) | O(1) | Signos y magnitudes muy variables |
No hay un ganador absoluto. La elección depende de precisión, rendimiento, memoria, paralelismo y estructura de los datos.
13 · Caso resuelto
Incrementos absorbidos por una magnitud grande
Consideremos 1e16, mil valores iguales a 1 y finalmente −1e16. La suma real es 1000.
const valores = [1e16, ...Array(1000).fill(1), -1e16];
console.log({
ingenua: valores.reduce((s, x) => s + x, 0),
kahan: sumaKahan(valores),
neumaier: sumaNeumaier(valores),
exacta: 1000
});La suma ingenua puede perder cada unidad mientras el acumulador vale 1e16. Los métodos compensados conservan, con distinto grado de robustez, información que el acumulador principal no pudo representar.
14 · Antes de sumar
Reformular puede ser mejor que compensar
La primera defensa numérica consiste en evitar una expresión inestable. Por ejemplo, para x pequeño, calcular:
provoca cancelación. Racionalizar produce la forma equivalente:
que conserva mejor las cifras significativas. De forma similar, Math.expm1(x) evalúa eˣ−1 y Math.log1p(x) evalúa ln(1+x) con precisión para x cercano a cero.
Un buen algoritmo de suma no compensa una fórmula previa mal condicionada si existe una identidad algebraica estable.
15 · Rango finito
Desbordamiento y subdesbordamiento
La precisión no es el único límite. Una operación puede producir Infinity aunque el resultado final exacto sea finito, o puede redondear valores extremadamente pequeños a cero.
console.log({
desbordaAntesDeCancelar: Number.MAX_VALUE * 2 - Number.MAX_VALUE * 2,
minimoPositivo: Number.MIN_VALUE,
mitadDelMinimo: Number.MIN_VALUE / 2
});Reordenar, factorizar una escala común o trabajar con logaritmos puede evitar valores intermedios fuera del rango. Una vez que aparece Infinity o un cero por subdesbordamiento, la suma compensada no recupera la información.
16 · Sumas infinitas truncadas
Combinar error analítico y error numérico
Al aproximar una serie mediante Sₙ intervienen dos desviaciones:
El primer término es el error de truncamiento estudiado en el tema anterior. El segundo es el error de acumulación en coma flotante.
Una estrategia completa asigna parte del presupuesto de error a cada componente. No tiene sentido exigir un resto inferior a 10⁻²⁰ si la representación y el algoritmo solo sostienen una precisión absoluta de 10⁻¹⁵ en esa escala.
17 · Criterio operativo
Cuando el término deja de cambiar la suma
La condición suma + término === suma detecta estancamiento numérico, no convergencia matemática. Puede ocurrir porque el término es menor que media unidad de espaciado del acumulador, aunque la cola contenga millones de términos del mismo signo.
Una parada confiable debería combinar:
- una cota matemática para el resto;
- una tolerancia absoluta y/o relativa bien definida;
- un límite de iteraciones como medida de seguridad;
- una advertencia si la suma se estanca antes de alcanzar la cota.
El estancamiento es información diagnóstica: puede indicar que hace falta otra fórmula, una escala diferente o mayor precisión.
18 · Pruebas numéricas
Cómo evaluar un sumador
Una prueba útil incluye datos adversos con resultado conocido, no solo entradas aleatorias. Conviene ensayar:
- magnitudes iguales y signos opuestos;
- un número grande rodeado de muchos incrementos pequeños;
- permutaciones de los mismos datos;
- cantidades positivas con gran rango dinámico;
- vectores vacíos, un solo elemento, ceros e infinitos según el contrato.
Para sumas de enteros construidas dentro de un rango controlado, BigInt puede proporcionar una referencia exacta. Para datos reales generales se necesita aritmética de mayor precisión o una biblioteca especializada.
19 · Exploración interactiva
Laboratorio: cinco formas de acumular
Elegí un patrón adverso y modificá su tamaño. Las barras muestran el error absoluto de cada algoritmo respecto de una suma exacta conocida.
Errores de sumación
10¹⁶ + 1 + ··· + 1 − 10¹⁶
Las unidades pueden desaparecer mientras el acumulador vale 10¹⁶.
Las barras comparan suma ingenua, orden inverso, suma por pares, Kahan y Neumaier; una barra mínima indica error cero.
20 · Comprensión
Confusiones frecuentes
«Number.EPSILON es el error de cualquier operación»
No. Describe el espaciado relativo cerca de 1; el error absoluto depende de la escala y de las operaciones.
«La suma compensada siempre devuelve el valor exacto»
No. Reduce mucho ciertos errores, pero sigue operando con precisión finita.
«Ordenar siempre mejora una suma con signos»
No necesariamente. La cancelación y el patrón de signos pueden hacer preferible otra agrupación o un método compensado.
«Si dos órdenes producen resultados distintos, la serie es condicional»
No. Una suma finita puede variar por redondeo; la sensibilidad matemática de una serie condicional es otro fenómeno.
«Más términos siempre dan una mejor aproximación»
Disminuyen el truncamiento de una serie convergente, pero también agregan operaciones y error de redondeo.
«Kahan reemplaza una fórmula numéricamente estable»
No. Primero conviene reformular expresiones inestables; después se elige cómo acumular.
21 · Práctica y síntesis
Ejercicios de precisión
Ejercicio 1: asociatividad
Predecí los resultados de (1e16 + 1) - 1e16 y 1e16 + (1 - 1e16) en JavaScript.
Ver solución
El primero suele producir 0 porque 1e16+1 se redondea a 1e16. El segundo también produce 0 en doble precisión para estos valores. En cambio, (1e16-1e16)+1 produce 1.
Ejercicio 2: ordenar positivos
¿Por qué sumar [1e16, 1, 1, 1] en orden inverso puede ser mejor?
Ver solución
Las tres unidades se combinan primero y forman 3, una cantidad con más posibilidades de sobrevivir al sumarse a 1e16. Aun así, el resultado almacenado queda limitado por el espaciado alrededor de 1e16.
Ejercicio 3: elegir algoritmo
Se reciben millones de mediciones en flujo y no pueden almacenarse. ¿Qué método resulta razonable?
Ver solución
Kahan o Neumaier: ambos son lineales y requieren memoria constante. Neumaier suele ser más robusto si cambian mucho los signos y magnitudes.
Ejercicio 4: dos errores
Explicá por qué una cota del resto de 10⁻¹² no garantiza por sí sola doce decimales correctos.
Ver solución
La cota controla el truncamiento exacto. Falta considerar la representación de los términos, el redondeo durante la suma y la escala del resultado.
Ejercicio 5: parada
¿Qué informa la igualdad suma + término === suma?
Ver solución
Que ese término no cambia el número representable almacenado en la escala actual. No demuestra que los términos restantes sumen una cantidad despreciable.
Ideas para recordar
- La aritmética de coma flotante redondea después de cada operación.
- La suma finita deja de ser asociativa en la máquina.
- El espaciado entre números representables aumenta con la magnitud.
- La suma por pares reduce la profundidad de acumulación y facilita el paralelismo.
- Kahan conserva una corrección local; Neumaier refuerza el manejo de magnitudes variables.
- Reformular una expresión inestable puede aportar más que cambiar el sumador.
- En una serie truncada deben presupuestarse tanto el resto como el error numérico.
- Los casos adversos con resultado conocido son esenciales para validar una implementación.
En el próximo tema volveremos a introducir una variable en la suma y estudiaremos las series de potencias como representaciones de funciones.