El error de conversión de unidades de $327 millones
El 23 de septiembre de 1999, el Mars Climate Orbiter de la NASA encendió sus motores para entrar en órbita marciana y nunca más se supo de él. La nave entró demasiado bajo — 57 km de altitud en vez de los 226 km planeados — y se quemó en la atmósfera o rebotó hacia el espacio. La causa: el software terrestre de Lockheed Martin producía datos de fuerza de propulsión en libra-fuerza por segundo, pero el software de navegación de la NASA esperaba newton por segundo. Nadie detectó la discrepancia durante 9 meses de vuelo.
El factor de conversión es simple: 1 libra-fuerza = 4.44822 newtons. El software estaba desfasado por un factor de 4.45× en cada maniobra de corrección de trayectoria. Cada pequeño error se acumuló a lo largo de millones de kilómetros. La junta de investigación lo llamó "una falla en el uso de unidades métricas en la codificación de un archivo de software terrestre." La falla real fue sistémica — ninguna especificación de interfaz definía las unidades, ninguna validación verificaba que los valores estuvieran en el rango esperado, y ninguna prueba de integración detectó la discrepancia.
Esto no fue un caso aislado. Los errores de conversión de unidades han causado el incidente del Gimli Glider (1983, un Boeing 767 de Air Canada se quedó sin combustible porque la tripulación de tierra calculó el combustible en libras en vez de kilogramos), el hundimiento del barco Vasa (1628, construido con dos sistemas de medición diferentes en babor y estribor), y el descarrilamiento del Space Mountain de Tokyo Disneyland (2003, especificaciones de eje en pulgadas interpretadas como milímetros). El patrón siempre es el mismo: dos sistemas, dos convenciones de unidades, ningún contrato explícito entre ellos.
Por qué los errores de conversión de unidades siguen pasando
El problema fundamental: los números sin unidades no tienen significado, pero la mayoría de los lenguajes de programación los tratan como números desnudos. Cuando escribes distance = 384400, ¿son kilómetros (Tierra a Luna) o millas (lo que te pondría 235,000 km más allá de la Luna)? El nombre de la variable puede decir "distance_km" pero nada en el sistema de tipos lo impone. Una función que espera metros aceptará felizmente un valor en pies y producirá basura sin ningún error.
La división métrico-imperial lo empeora. EE.UU., Myanmar y Liberia son los únicos países que no han adoptado oficialmente el sistema métrico. Pero incluso en países métricos, los sistemas legacy usan unidades imperiales — la aviación usa pies para altitud y millas náuticas para distancia en todo el mundo. La medicina usa ambos (presión arterial en mmHg, temperatura corporal en °F en EE.UU. pero °C en el resto). Esto significa que cualquier sistema internacional debe manejar ambos, y el límite de conversión es donde viven los bugs.
Trampas específicas del software: CSS usa px, em, rem, vh, vw — todas unidades diferentes para longitud. Las APIs devuelven temperaturas en Kelvin, Celsius o Fahrenheit dependiendo del proveedor. Los timestamps vienen en segundos, milisegundos o microsegundos. Los ángulos pueden ser grados, radianes o gradianes. Cada vez que cruzas un límite entre sistemas, librerías o APIs, estás en riesgo de un desajuste de unidades.
El factor humano: los errores de conversión de unidades son aburridos. No son bugs ingeniosos — son errores mundanos que se sienten demasiado simples para ocurrir. Exactamente por eso se escapan en la revisión de código. Un revisor ve "thrust = calculateThrust(data)" y no piensa en preguntar "¿en qué unidades está data?" El equipo del Mars Orbiter tenía cientos de ingenieros y 9 meses de operaciones de vuelo. Nadie hizo la pregunta.
Errores comunes de conversión de unidades en software
Temperatura: La fórmula C = (F - 32) × 5/9 es simple, pero la división entera en algunos lenguajes trunca el resultado. En C: (100 - 32) * 5 / 9 = 37 (correcto), pero (50 - 32) * 5 / 9 = 10 (debería ser 10.0, pero bastante cerca). La trampa real: Kelvin a Celsius es solo K - 273.15, pero Kelvin a Fahrenheit requiere dos pasos. Y Rankine (usado en alguna ingeniería de EE.UU.) es Fahrenheit + 459.67. Nuestra herramienta scientific-calculator maneja las cuatro escalas.
Distancia: 1 milla = 1.60934 km, 1 pie = 0.3048 metros exactamente (por definición desde 1959), 1 pulgada = 25.4 mm exactamente. El "exactamente" importa — estas son conversiones definidas, no aproximaciones medidas. Pero las millas náuticas (1.852 km) son diferentes de las millas terrestres (1.609 km), y una "milla" en el Reino Unido era históricamente diferente de una milla estadounidense hasta la estandarización. Siempre especifica qué milla.
Peso vs masa: En el lenguaje cotidiano, "peso" y "masa" son intercambiables. En física, la masa (kg) es intrínseca y el peso (newtons) depende de la gravedad. En la Tierra, 1 kg de masa pesa 9.81 N. En Marte, pesa 3.72 N. Esta distinción importa en aeroespacial, simulaciones de física y cualquier código que modele objetos en diferentes entornos gravitacionales. El error del Mars Orbiter fue específicamente sobre fuerza (newtons vs libra-fuerza), no masa.
Almacenamiento de datos: 1 KB = 1,000 bytes (SI, usado por fabricantes de discos duros) o 1,024 bytes (binario, usado por sistemas operativos). Por eso tu disco de "1 TB" muestra 931 GB en Windows. El estándar IEC introdujo KiB (1,024 bytes), MiB (1,048,576 bytes), etc. para resolver la ambigüedad, pero la adopción es inconsistente. Cuando tu código reporta tamaños de archivo, sé explícito sobre qué convención estás usando.
Estrategias de prevención que realmente funcionan
Estrategia 1: Usa un sistema de tipos que codifique unidades. En TypeScript, puedes usar branded types: type Meters = number & { __brand: "meters" }. Una función que espera Meters no aceptará un número plano sin casting explícito. Librerías como ts-units, unitful (Haskell) o Boost.Units (C++) imponen corrección de unidades en tiempo de compilación. El error del Mars Orbiter habría sido un error de compilación con tipos de unidades apropiados.
Estrategia 2: Siempre convierte a una unidad canónica en los límites del sistema. Elige un sistema de unidades (SI métrico es la elección estándar) y convierte todas las entradas a ese sistema inmediatamente al recibirlas. Los cálculos internos usan solo las unidades canónicas. Convierte de vuelta a unidades de visualización solo en el límite de salida. Este patrón "normaliza temprano, desnormaliza tarde" elimina la confusión interna de unidades.
Estrategia 3: Incluye unidades en nombres de variables y contratos de API. No solo "distance" sino "distance_meters". No solo "temperature" sino "temp_celsius". En documentación de API, especifica unidades explícitamente: "altitude: number (metros sobre el nivel del mar)". En esquemas de base de datos, agrega un comentario o usa nombres de columna como "weight_kg". Esto es low-tech pero atrapa errores durante la revisión de código.
Estrategia 4: Valida rangos en los límites. Una temperatura de 5,000°C para una lectura meteorológica es obviamente incorrecta — probablemente son 5,000 Kelvin que no se convirtieron, o 50.00°C con un decimal mal puesto. Una distancia de 384,400 para un viaje en auto probablemente son kilómetros cuando esperabas millas (o viceversa). Las verificaciones de rango atrapan errores de unidades que producen valores físicamente imposibles. Nuestra herramienta unit-converter muestra ambos valores lado a lado para que puedas verificar la magnitud.
// Branded types prevent unit confusion at compile time
type Meters = number & { readonly __brand: unique symbol };
type Feet = number & { readonly __brand: unique symbol };
function metersToFeet(m: Meters): Feet {
return (m * 3.28084) as Feet;
}
function calculateAltitude(alt: Meters): string {
return `${alt}m above sea level`;
}
const altitude = 10000 as Meters;
calculateAltitude(altitude); // ✅ OK
// calculateAltitude(10000 as Feet); // ❌ Type error!
// Simpler approach: objects with explicit unit field
interface Measurement {
value: number;
unit: 'meters' | 'feet' | 'km' | 'miles';
}
function toMeters(m: Measurement): number {
switch (m.unit) {
case 'meters': return m.value;
case 'feet': return m.value * 0.3048;
case 'km': return m.value * 1000;
case 'miles': return m.value * 1609.34;
}
}Conversión de unidades en computación científica
El código científico tiene un desafío adicional: unidades derivadas. La velocidad es metros/segundo, la aceleración es metros/segundo², la fuerza es kg·m/s² (newtons), la energía es kg·m²/s² (joules). Cuando multiplicas velocidad por tiempo, el resultado debería estar en metros — pero tu lenguaje de programación no lo sabe. El análisis dimensional (verificar que las unidades se cancelen correctamente) es algo que los físicos hacen en papel pero rara vez codifican en software.
La librería Pint (Python) y herramientas similares manejan esto: distance = 5 * ureg.meter; time = 2 * ureg.second; speed = distance / time te da 2.5 meter/second con seguimiento completo de unidades. Si intentas sumar metros y segundos, obtienes un DimensionalityError. Esto atrapa bugs que de otra forma producirían resultados sin sentido silenciosamente.
La precisión de punto flotante interactúa con la conversión de unidades de formas sutiles. La conversión exacta 1 pulgada = 25.4 mm es representable en punto flotante. Pero 1 pie = 0.3048 metros tiene una representación binaria repetitiva e introduce pequeños errores de redondeo. A lo largo de millones de conversiones (común en software CAD o simulaciones de física), estos errores se acumulan. Usa aritmética racional exacta para factores de conversión cuando la precisión importa.
Un ejemplo real: coordenadas GPS. Latitud/longitud en grados con 6 decimales da ~0.11 metros de precisión. Pero si conviertes a radianes para cálculos trigonométricos y de vuelta, el redondeo de punto flotante puede desplazar tu posición por centímetros. Para navegación esto está bien. Para topografía (donde los milímetros importan), necesitas tener cuidado con la precisión de conversión. Siempre convierte una vez y mantén el resultado, en vez de convertir de ida y vuelta repetidamente.
Cuando las herramientas de conversión de unidades no son suficientes
Algunas "conversiones" no son multiplicaciones simples. Temperatura (Celsius a Fahrenheit involucra un offset, no solo una razón). Decibeles (escala logarítmica — duplicar la potencia suma 3 dB, no duplica dB). pH (también logarítmico — pH 5 es 10× más ácido que pH 6). Escala Richter (cada número entero es 31.6× más energía). Estas requieren entender la escala subyacente, no solo un factor de conversión.
La conversión de moneda es un caso especial: el factor de conversión cambia cada segundo. Un "conversor de unidades" que usa una tasa fija está equivocado para cuando lo usas. La conversión real de moneda requiere tasas de cambio en vivo, y la tasa que obtienes depende del monto (spread), la dirección (tasa de compra vs venta) y el proveedor (banco vs broker forex vs tarjeta de crédito). Nuestra herramienta unit-converter maneja unidades físicas con factores de conversión fijos; para moneda, necesitas una API de tasas en vivo.
Las medidas de cocina son sorprendentemente complejas. Una "taza" es 236.6 mL en EE.UU., 250 mL en Australia y 200 mL en Japón. Una "cucharada" es 14.8 mL (EE.UU.), 15 mL (métrica) o 20 mL (Australia). Las recetas de diferentes países usan diferentes medidas "estándar". Y las conversiones de volumen a peso dependen del ingrediente: 1 taza de harina pesa 125g, pero 1 taza de azúcar pesa 200g. Ninguna tabla de conversión simple maneja esto.
La lección de todos estos casos borde: la conversión de unidades solo es "simple" para unidades físicas bien definidas con razones fijas. Para todo lo demás — monedas, cocina, escalas logarítmicas, unidades dependientes del contexto — necesitas conocimiento del dominio, no solo un factor de multiplicación. Las mejores herramientas de conversión de unidades (incluyendo la nuestra) son explícitas sobre lo que pueden y no pueden convertir, y señalan casos donde un factor simple no es suficiente.