Una memoria de cálculo firmada tiene que poder reproducirse. Si alguien vuelve a abrir el proyecto dentro de un año, o lo revisa otro ingeniero, el mismo modelo tiene que dar los mismos números, y tiene que quedar claro con qué versión del programa se obtuvieron.
Al medirlo encontramos que no siempre pasaba: dos cálculos del mismo modelo en la misma sesión podían diferir en los últimos dígitos, y algunos resultados salían en otro orden. Las diferencias eran pequeñísimas, pero un número que cambia sin que cambie nada es un número que no se puede verificar.
De dónde venía la diferencia
El motor guarda los nudos, las barras, los apoyos y las cargas en tablas hash, y cada tabla se crea con una semilla aleatoria: el mismo archivo leído dos veces se recorre en dos órdenes distintos. Sumar números de punto flotante en otro orden puede cambiar el último bit, porque la suma de computadora no es asociativa. Los ensambladores 3D ya ordenaban las barras, pero los 2D, los bucles de cargas y apoyos y la mayoría de los otros análisis no.
- Cada recorrido de una tabla de entrada pasa ahora por un orden fijo, el de sus claves: 587 lugares en todo el motor.
- Las sumas de equilibrio y los términos cruzados de los apoyos inclinados también se recorren en orden fijo.
- Las advertencias salen ordenadas por número de nudo o barra, no al azar.
| Qué | Cantidad |
|---|---|
| Recorridos de tablas de entrada puestos en orden fijo | 587 |
| Lecturas de cada modelo aleatorio comparadas bit a bit | 6 |
Una prueba lee cada modelo aleatorio seis veces, lo resuelve y compara los resultados como texto, bit a bit, en análisis lineales, modales, de pandeo y P-Delta. Un recorrido sin orden que cambie un resultado aparece como una diferencia entre las lecturas.
Cada memoria dice de dónde salió
Cada memoria de cálculo, memoria PRO, planilla y CSV lleva ahora un bloque de trazabilidad: versión y commit de la aplicación y del motor, la huella SHA-256 del módulo WebAssembly que hizo el cálculo, una huella del modelo exacto, de la configuración y de los resultados mostrados, y el estado de los certificados (la envolvente de cargas móviles registra menos: su modelo y su configuración). Si el proyecto cambió mientras se preparaba la exportación, no se exporta: una memoria nunca lleva los números de un estado con la trazabilidad de otro.
Con ese bloque, la aplicación puede reproducir una memoria: vuelve a resolver el proyecto y compara cada huella. El resultado es «reproducido» sólo si todas coinciden (una versión distinta del módulo WebAssembly se informa al lado, no cuenta como diferencia); si una no se pudo recalcular, dice «incompleto», nunca «reproducido». También hay una herramienta de línea de comandos que resuelve dos veces la misma entrada y verifica las huellas.
Los proyectos viejos avisan
Cada proyecto guardado lleva la versión de resultados con que se calculó. Cuando se abre un proyecto calculado antes de un cambio que afecta a sus características, la aplicación lista esos cambios, explicados en tu idioma, y marca los resultados como desactualizados hasta volver a calcular. Ante la duda, un cambio se considera aplicable: un aviso de más cuesta un minuto, uno de menos puede esconder un número que cambió.
Un límite
La aplicación siempre compara WebAssembly contra WebAssembly. La herramienta nativa reprodujo bit a bit las huellas del navegador en el modelo de prueba, pero las funciones trigonométricas vienen de bibliotecas distintas en cada plataforma, así que un modelo cuyo ensamblado las use de una forma que las dos redondeen distinto podría diferir en el último bit entre la línea de comandos y el navegador.