Skip to content

Fix #24: render non-integer floats in shortest round-trippable form#25

Merged
pyrex41 merged 1 commit into
mainfrom
fix/float-shortest-roundtrip-24
Jun 14, 2026
Merged

Fix #24: render non-integer floats in shortest round-trippable form#25
pyrex41 merged 1 commit into
mainfrom
fix/float-shortest-roundtrip-24

Conversation

@pyrex41

@pyrex41 pyrex41 commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Fixes #24.

Non-integer floats were printed via LuaJIT's tostring (%.14g), which is lossy and not the shortest round-trippable form: (+ 0.1 0.2) printed 0.3 instead of the actual double 0.30000000000000004, diverging from shen-cl / shen-rust / shen-go / ShenScript.

Fix: a shortest_float helper in runtime.lua emits the smallest %.<p>g (p = 1..17) whose tonumber() parses back to exactly the same double. Both the canonical str/print path (numToStr in prims.lua) and the REPL/debug printer (to_str in runtime.lua) route through it. Integer-valued floats still print bare via the existing %d branch; kernel/klambda untouched.

Verification:

(str (+ 0.1 0.2))  => 0.30000000000000004   (was 0.3)
(str (/ 10 4))     => 2.5
(str (+ 3.5 1.25)) => 4.75
(str 2.0)          => 2                       (integer-valued float unchanged)

make test 448 pass / 0 fail (incl. new #24 regression assertions in primitives_spec.lua); make certify 134/134 (100%).

This is the last of the three float-formatting divergences tracked by bifrost — with this + pyrex41/shen-go#11, all five impls now agree, and bifrost's float cases are promoted from documented divergences to hard agreement assertions (pyrex41/bifrost#1 / verify/converged-divergences). Verified end-to-end: a combined tree (this fix + the #22 hush fix) runs bifrost fully green (30 pass, 0 diverge, 0 FAIL).

🤖 Generated with Claude Code

LuaJIT's tostring / %g defaults to 14 significant digits, so numToStr (and the
debug printer to_str) printed (+ 0.1 0.2) as "0.3" instead of the actual double
"0.30000000000000004" — a lossy, non-round-tripping form that diverged from
shen-cl/shen-rust/shen-go/ShenScript.

Add a shortest_float helper (runtime.lua) that emits the smallest %.<p>g
(p = 1..17) whose tonumber() parses back to exactly the same double, and route
both numToStr (the str/print path) and to_str (the REPL/debug printer) through
it. Integer-valued floats still print bare via the existing %d branch; kernel/
klambda untouched.

Verified: (str (+ 0.1 0.2)) => 0.30000000000000004, (str (/ 10 4)) => 2.5,
(str (+ 3.5 1.25)) => 4.75. make test 448 pass / 0 fail; make certify 100%.
bifrost float cases (int-div-to-float, float-add-clean, float-add-imprecise)
now agree across all five impls.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pyrex41 pyrex41 merged commit 7d18096 into main Jun 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Non-integer floats print via %.14g, not shortest round-trip (diverges from other ports)

1 participant