Uma memória de cálculo assinada tem que poder ser reproduzida. Se alguém reabrir o projeto daqui a um ano, ou se outro engenheiro o revisar, o mesmo modelo tem que dar os mesmos números, e tem que ficar claro com que versão do programa eles foram obtidos.
Ao medir isso descobrimos que nem sempre acontecia: dois cálculos do mesmo modelo na mesma sessão podiam diferir nos últimos dígitos, e alguns resultados saíam em outra ordem. As diferenças eram minúsculas, mas um número que muda sem que nada tenha mudado é um número que não pode ser verificado.
De onde vinha a diferença
O motor guarda os nós, as barras, os apoios e as cargas em tabelas hash, e cada tabela é criada com uma semente aleatória: o mesmo arquivo lido duas vezes é percorrido em duas ordens diferentes. Somar números de ponto flutuante em outra ordem pode mudar o último bit, porque a soma do computador não é associativa. Os montadores 3D já ordenavam as barras, mas os 2D, os laços de cargas e apoios e a maioria das outras análises não.
- Cada percurso de uma tabela de entrada passa agora por uma ordem fixa, a de suas chaves: 587 lugares em todo o motor.
- As somas de equilíbrio e os termos cruzados dos apoios inclinados também são percorridos em ordem fixa.
- Os avisos saem ordenados por número de nó ou barra, não ao acaso.
| O quê | Quantidade |
|---|---|
| Percursos de tabelas de entrada postos em ordem fixa | 587 |
| Leituras de cada modelo aleatório comparadas bit a bit | 6 |
Um teste lê cada modelo aleatório seis vezes, o resolve e compara os resultados como texto, bit a bit, em análises lineares, modais, de flambagem e P-Delta. Um percurso sem ordem que mude um resultado aparece como uma diferença entre as leituras.
Cada memória diz de onde saiu
Cada memória de cálculo, memória PRO, planilha e CSV leva agora um bloco de rastreabilidade: versão e commit do aplicativo e do motor, a impressão digital SHA-256 do módulo WebAssembly que fez o cálculo, uma impressão do modelo exato, da configuração e dos resultados mostrados, e o estado dos certificados (a envoltória de cargas móveis registra menos: seu modelo e sua configuração). Se o projeto mudou enquanto a exportação era preparada, nada é exportado: uma memória nunca leva os números de um estado com a rastreabilidade de outro.
Com esse bloco, o aplicativo pode reproduzir uma memória: resolve o projeto de novo e compara cada impressão. O resultado é «reproduzido» só quando todas coincidem (uma versão diferente do módulo WebAssembly é informada ao lado, não conta como diferença); quando uma não pôde ser recalculada, diz «incompleto», nunca «reproduzido». Também há uma ferramenta de linha de comando que resolve duas vezes a mesma entrada e verifica as impressões.
Os projetos antigos avisam
Cada projeto salvo registra a versão de resultados com que foi calculado. Quando se abre um projeto calculado antes de uma mudança que afeta suas características, o aplicativo lista essas mudanças, explicadas no seu idioma, e marca os resultados como desatualizados até calcular de novo. Na dúvida, uma mudança conta como aplicável: um aviso a mais custa um minuto, um a menos pode esconder um número que mudou.
Um limite
O aplicativo sempre compara WebAssembly com WebAssembly. A ferramenta nativa reproduziu bit a bit as impressões do navegador no modelo de teste, mas as funções trigonométricas vêm de bibliotecas diferentes em cada plataforma, então um modelo cuja montagem as use de um jeito que as duas arredondem diferente poderia diferir no último bit entre a linha de comando e o navegador.