Números, unidades y precisión: evitar errores de redondeo en datos BIM
Tres superficies pueden mostrarse como 10,00 m² y no cumplir la misma condición. Una vale 9,9999; otra, exactamente 10; la tercera, 10,0001. Si el requisito del ejercicio es alcanzar 10 m², la primera queda por debajo. Redondearla antes de comprobarla no mejora el espacio: mejora su expediente. Me parece una contribución bastante peculiar de la informática al diseño.
Vamos a separar tres decisiones que suelen acabar mezcladas: en qué unidad llega un dato, con qué representación lo calculamos y cómo lo mostramos. Utilizaremos superficies recibidas como texto en m² y mm², un umbral didáctico y ejemplos completos de Python y C#. No estamos verificando una norma ni midiendo geometría de un modelo: vamos a construir una comparación que no cambie de criterio por decorar la salida.
Primero la magnitud y la unidad; después la comparación
El número 10000000 no describe por sí solo una superficie. Si son milímetros cuadrados, equivale a 10 metros cuadrados. Si lo comparas directamente con el umbral 10 m², estás mezclando unidades. El programa puede ejecutar esa comparación sin problemas porque ambos valores son números; la incoherencia pertenece al significado que les has asignado. Que una operación esté permitida por el lenguaje es una garantía bastante modesta para un cálculo de proyecto.
Para pasar de mm² a m² dividimos entre un millón. Un metro tiene mil milímetros, pero una superficie combina dos dimensiones: 1000 por 1000. Dividir entre mil como si estuviéramos convirtiendo una longitud produce un resultado mil veces mayor del correcto. Antes de discutir cuántos decimales necesitamos, conviene asegurarse de que estamos calculando la magnitud que creemos. La precisión no compensa una unidad equivocada; solo permite equivocarse con más detalle.
Elegiremos m² como unidad común y convertiremos cada entrada antes de compararla. Conservaremos también el identificador, el texto recibido y su unidad para poder investigar cualquier resultado. En una aplicación real, la unidad debe proceder del contrato de la fuente o de sus metadatos, no de que el número parezca grande. Una superficie pequeña expresada en mm² y una grande en m² pueden desmontar con bastante facilidad un detector basado en intuiciones.
El umbral será 10 m² y aceptaremos los valores mayores o iguales. Es una regla inventada para aprender el mecanismo; no representa una exigencia normativa de un espacio. Si el requisito real define otra magnitud, un método de medición o una tolerancia, tendrás que aplicarlos expresamente. No los incorpora una comparación >= por tener una apariencia tan decidida.
Representar el número y mostrarlo son trabajos distintos
Entre los tipos de datos numéricos, los binarios habituales, como float en Python o double en C#, no representan exactamente todos los decimales. Eso no los convierte en tipos defectuosos: son adecuados para muchos cálculos, pero exigen entender su aproximación. La explicación oficial de Python sobre coma flotante desarrolla esa diferencia. Añadir ceros a una impresión no cambia el valor almacenado ni elimina la incertidumbre de una medida.
Para este intercambio de textos decimales elegiremos Decimal en Python y decimal en C#. Partiremos del texto original, sin convertir primero a un número binario. El ejercicio utiliza operaciones y valores dentro de un rango acotado que podemos representar con precisión decimal. Eso no significa que estos tipos sean ilimitados, que cualquier división resulte exacta o que debas sustituir automáticamente los tipos que utiliza una API geométrica. La elección depende de los datos y de las operaciones, no de coronar un ganador universal.
También fijaremos un contrato de entrada estrecho: texto con entre uno y doce dígitos enteros y, opcionalmente, un punto seguido de entre uno y seis decimales. Sin separadores de miles, signos, espacios ni exponentes. Las unidades admitidas serán exactamente m2 y mm2. Esta restricción deja el cálculo dentro de un rango manejable en ambos lenguajes y hace visibles los errores de formato. No es un lector de cualquier exportación que aparezca en una carpeta.
En la salida mostraremos dos decimales con redondeo al par en los empates. Por ejemplo, 10.005 se presenta como 10.00 y 10.015 como 10.02. Es una política elegida para este informe, no una obligación para todos los proyectos. La clasificación usará el valor convertido antes de ese redondeo. El informe debe explicar esa separación porque dos cifras visualmente iguales pueden llevar estados diferentes sin que exista contradicción.
Python: convertir, decidir y formatear en ese orden
Guarda el programa como superficies.py. Necesita Python 3 y utiliza módulos de su biblioteca estándar. area_m2 comprueba el formato y la unidad, crea el decimal a partir del texto y devuelve la superficie convertida. El bucle decide el estado con ese resultado completo; solo después prepara el número que se verá en pantalla. Separar esa conversión en una función con entradas y resultado explícitos permite comprobarla sin depender del formato del informe.
Ejecútalo desde su carpeta:
Obtendrás A con 10.00 m2 | por debajo, B con 10.00 m2 | cumple y C con 10.00 m2 | cumple. En esta salida utilizamos punto decimal para que el formato sea reproducible; el texto del artículo emplea también la coma habitual en español. A conserva internamente 9.9999 m², aunque su presentación sea 10.00. La regla no consulta visible: consulta area. Esa diferencia de una variable concentra la decisión que queríamos proteger.
quantize prepara un valor con dos posiciones decimales y la política indicada. Si reutilizaras ese valor para clasificar, A pasaría a cumplir por un efecto de presentación. No es un error de coma flotante: también podrías introducirlo trabajando con aritmética decimal exacta. Elegir un tipo adecuado no te libra de ordenar las operaciones con criterio. La referencia de decimal explica el contexto de precisión y las opciones de redondeo cuando necesites ampliar este ejemplo.
La validación del texto rechaza una coma decimal, un espacio o NaN en vez de transformarlos silenciosamente. Si la fuente real utiliza coma, prepara un lector acorde con su formato documentado y conserva lo recibido. Cambiar todos los puntos y comas sin distinguir decimal y millar es una forma especialmente creativa de fabricar superficies nuevas. Para eso ya tenemos herramientas de diseño; el importador debería limitarse a entender la entrega.
C#: mantener el mismo contrato con decimal
Crea un proyecto de consola de .NET 8:
Reemplaza Superficies/Program.cs por el programa siguiente. La expresión regular utiliza inicio y final absolutos de texto, y decimal.Parse recibe cultura invariante para el punto decimal. El sufijo m de las constantes indica el tipo decimal; no significa metros. La unidad la establece nuestra función y su divisor, no una letra con una coincidencia afortunada.
Ejecuta el proyecto:
La salida coincide con Python para los tres registros. MidpointRounding.ToEven hace explícita la misma decisión sobre empates; la referencia oficial de MidpointRounding explica sus modos. El formato F2 muestra las dos posiciones decimales después de redondear. La condición de cumplimiento sigue evaluándose antes, sobre area.
Los límites elegidos en el formato de entrada evitan admitir una cantidad arbitraria de cifras que después pudiera perder precisión al interpretarse o calcularse. Si tu intercambio exige otro rango, cambia y prueba ese contrato en ambos extremos. Declarar una variable como decimal no obliga a un sistema externo a enviar una representación compatible. Es precisamente el tipo de detalle que suele desaparecer de una demo y reaparecer durante la entrega.
Probar la frontera sin inventar una tolerancia
Comprueba tres valores en m²: 9.9999, 10 y 10.0001. Después expresa esas mismas superficies en mm²: 9999900, 10000000 y 10000100. La conversión debe producir las mismas decisiones, independientemente de la unidad de entrada. Es una prueba más útil que comprobar únicamente si un número muy grande queda por encima del umbral. Los errores de factor suelen sobrevivir con bastante comodidad a los ejemplos que están lejos del límite.
Prueba también 10.005 y 10.015 para comprobar los empates de presentación, y conserva ambos como valores que cumplen. Después introduce 10,5, una unidad desconocida y un número con más de seis decimales: el programa debe rechazar esas entradas bajo el contrato publicado. Rechazarlas no demuestra que esas representaciones sean incorrectas en cualquier contexto; indica que este lector no las admite. Esa diferencia permite ampliar la herramienta sin convertir sus límites en una teoría universal del dato.
Una tolerancia tiene otro propósito. Si decides aceptar una pequeña desviación por el método de cálculo o la precisión de la fuente, define qué diferencia admites y en qué unidad, y justifica por qué corresponde al requisito. No añadas un margen minúsculo porque «los decimales dan problemas», ni uses el formato de pantalla como tolerancia involuntaria. Puedes necesitar un criterio de proximidad para comparar resultados geométricos, pero eso no autoriza a rebajar un umbral del proyecto sin acuerdo.
Al llevar esta regla a un modelo real también necesitarás conocer cómo obtiene la superficie la aplicación y cómo expresa sus unidades. Estos programas reciben textos y unidades explícitas; no acreditan conversiones ni cálculos en una API BIM. Conservar el original, el valor normalizado y el criterio aplicado permite explicar qué decidió el informe. Dos decimales son suficientes para leer muchas tablas; rara vez son una explicación suficiente de por qué una superficie pasa o falla. Esa explicación debe estar en la regla, antes de que la tipografía empiece a conceder metros cuadrados.
Respuestas