Typed-struct float32 optimization can lose ≤1 ULP on non-canonical doubles
还没有人认领这个 Issue。
评估
- 难度
- 5/5
- 预计耗时
- 一周以上
- 新手友好度
- 25/100
- Issue 类型
- 缺陷
- 描述清晰度
- 需要澄清
- 活跃度
- 冷清
- 技术栈
- javascript
- 领域
- backend
调研方向
从 typed-struct randomAccessStructure number path 开始,将其与 msgpackr v1 的 struct.js 进行比较,然后运行提供的 JavaScript 复现代码。Done 未定义:该 issue 明确跟踪一项延期变更,而任何实现都需要达成一致的兼容性决策,并添加针对精确往返和字节级相同输出的测试。
由索引模型根据 Issue 内容生成。
描述
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.
- 主要语言
- JavaScript
- 星标
- 13
- 派生
- 1
- 平均合并
- 4 天 3 小时
- 30 天内合并 PR
- 2
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 77/100
jasonacox/pypowerwall#472 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
sebastienros/jint#4531 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
ome/ngff-rfc8-revisions#50 ·
维护者通常 3 天内回复
-
[Bug] Root filesystem scope (/) incorrectly rejects all descendant paths可能已有人在做 @mugenkyou 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 72/100
neutralinojs/neutralino.js#304 · 1 条评论 ·