Typed-struct float32 optimization can lose ≤1 ULP on non-canonical doubles
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 5/5
- Tempo estimado
- Mais de uma semana
- Facilidade para iniciantes
- 25/100
- Tipo de issue
- Bug
- Clareza
- Precisa de esclarecimento
- Status de atividade
- Pouca atividade
- Stack de tecnologia
- javascript
- Domínio
- backend
Direção de pesquisa
Comece pelo number path de typed-struct randomAccessStructure e compare-o com o struct.js do msgpackr v1; em seguida, execute a reprodução em JavaScript fornecida. Done não está definido: o issue acompanha explicitamente uma alteração adiada, e qualquer implementação exigiria uma decisão de compatibilidade acordada, além de testes para round trips exatos e saída idêntica byte a byte.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Summary
The typed-struct (randomAccessStructure) number path stores certain float64 values as a 4-byte float32 field and reconstructs them on decode using the significant-digit rounding heuristic (the mult10 table). For a double that is not the canonical shortest-decimal representative of its decimal value, decode returns the canonical neighbor instead — a loss of up to 1 ULP.
This is the deliberate msgpackr float32 optimization carried over byte-for-byte from msgpackr's struct.js (it is not a structon regression — structon's output is byte-identical to msgpackr v1.11's native randomAccessStructure here). Filing as a tracking issue per discussion; no fix planned right now.
Scope
- Only the typed-struct path is affected. Plain msgpackr/cbor-x number encoding preserves the exact double.
- The same behavior exists in msgpackr v1's
struct.js(the deployed 5.0.x code), so any future change should be considered jointly.
Reproduction
import { Packr } from 'msgpackr';
import { createStructon } from 'structon';
const S = createStructon(Packr);
const enc = new S({ randomAccessStructure: true, useRecords: false });
const v = 1000.0001000000001; // a double adjacent to the 1000.0001 literal
const out = enc.decode(enc.encode({ x: v })).x;
console.log(out); // 1000.0001
console.log(Object.is(out, v)); // false (decoded to the canonical neighbor)
console.log(1000.0001 === v); // false (they are distinct doubles)
1000.0001 (the canonical literal) round-trips exactly; only the non-canonical neighbor canonicalizes.
Why it happens
In the number case, a float32-range value is written as float32, then accepted as num32 if number * mult10[exp] is an integer. That check passes for both a nice decimal and its ULP-adjacent neighbors, so the neighbor decodes to the nice-decimal double.
Possible fix (deferred)
Tighten the float32-acceptance check to require an exact round-trip (decode(float32-bytes) === number) before choosing num32, falling through to float64 otherwise. This would diverge from msgpackr v1's bytes (breaks the byte-identical-output property the test suite asserts), so it's a deliberate-optimization change, not a drop-in fix.
Impact
Low: ≤1 ULP (~1e-13 relative), only on the struct path, only for non-canonical doubles. Not a correctness concern for typical data (e.g. it did not contribute to the typed-struct memory blowup tracked separately).
Filed by Claude (Opus 4.7) on behalf of @kris-zyp during the typed-struct memory investigation.
- Linguagem predominante
- JavaScript
- Estrelas
- 13
- Forks
- 1
- Merge médio
- 4d 3h
- PRs com merge (30d)
- 2
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Sem modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Issues semelhantes
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
home-sweet-gnome/dash-to-panel#2594 ·
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 84/100
agentic-community/mcp-gateway-registry#2017 ·
Mantenedores costumam responder em até 1 dia
-
P2 Team S Type: Bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
google/site-kit-wp#14138 ·
Mantenedores costumam responder em até 2 dias
-
0. Needs triage bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
Mantenedores costumam responder em até 1 dia
-
from-agent
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 65/100