feat(runtime,backend): Float32 arithmetic, compare, Show and narrowing from Float64 #352

Merged
argus merged 1 commit from loop/35-float32-arithmetic into main 2026-10-12 22:54:51 +00:00
Collaborator

Task: #35 (slice 1: Float32 arithmetic, comparison, text and narrowing from Float64).

What

  • Runtime: torb_parse_f32 (reads a Float64, rounds once, a finite text beyond the range is an infinity as for Float64), torb_show_f32 now searches the shortest text that reads back to the same float, and torb_convert_f64_f32_checked (ties to even, nan/inf pass through, fails only from 2^128 - 2^103 on, with an explicit check so no out-of-range double to float cast happens).
  • Manifest (backend/c/natives.trb): the planned Float32 rows become ready - numericMembers, signedMembers and compare (torb_compare_f32) like Float64 - plus the new row Float32.tryFrom(Float64). runtime/machine_natives.c and torb_natives.h regenerated for the four runtime rows (263 thunks).
  • VM thunks: a float * out-parameter goes through a temporary, because a register holds a float as the bits of the double it equals.
  • Layout: a Float32 interpolation part is the text of its Show (torb_show_f32), not the Float64 formatter.
  • Constant folding (ir/constant.trb, bytecode emit.trb): a Float32 result is rounded to binary32 (via std/binary/number's float32Pattern), so a folded constant has the bits the run time computes; an integer literal typed as a float now folds as a float (const x: Float32 = 1 / 3 is 0.33333334, not 0).
  • std/number: extend Float32 with TryFrom<Float64, NumberRangeError>, the Float32 type doc and Real "# Open" updated. std/encoding's Float32 comment updated.
  • Docs: LINEAR.md item 8, ROADMAP planned natives, RELEASE.md rows, BACKEND.md NativeState/gap 18, number.md (declarations + prose), binary.md, BINARY.md; skills/ references mirrored.

Seed rule: new natives only, one commit; nothing in std/ or the compiler uses them (the migration of std/binary is #349, bits()/ofBits #348).

Not changed: the checker's own constant evaluator (semantics/checker/constant.trb) still computes a Float32 constant in Float64; it only feeds diagnostics.

Test

  • New conformance program tests/conformance/float32.trb: the 32-vs-64-bit sum, 2^24+1 / 2^24+3 rounding, %, negation, absolute, overflow to inf, subnormals, signed zero, nan comparisons and compare, the parse/show round trip, narrowing at the edges (halfway to 2^128, 3.5e38, 1e-50, nan/inf), and constant folding equal to the run time. Expectations computed with binary32 rounding outside the toolchain.
  • floats.trb: the Float32 line now also shows the named constants.
  • Runtime C tests for torb_show_f32/torb_parse_f32 and torb_convert_f64_f32_checked.
  • No local toolchain build (machine load); all gates ran in this PR's CI and are green (tier A, tier B with the conformance suite native and in the VM). Allocation budgets from the CI report: float32 82 blocks, floats 28 -> 34 (its new line shows the five named Float32 constants).

Closes #35

Task: #35 (slice 1: Float32 arithmetic, comparison, text and narrowing from Float64). ## What - **Runtime**: `torb_parse_f32` (reads a `Float64`, rounds once, a finite text beyond the range is an infinity as for `Float64`), `torb_show_f32` now searches the shortest text that reads back to the same `float`, and `torb_convert_f64_f32_checked` (ties to even, nan/inf pass through, fails only from 2^128 - 2^103 on, with an explicit check so no out-of-range `double` to `float` cast happens). - **Manifest** (`backend/c/natives.trb`): the planned Float32 rows become ready - `numericMembers`, `signedMembers` and `compare` (`torb_compare_f32`) like `Float64` - plus the new row `Float32.tryFrom(Float64)`. `runtime/machine_natives.c` and `torb_natives.h` regenerated for the four runtime rows (263 thunks). - **VM thunks**: a `float *` out-parameter goes through a temporary, because a register holds a `float` as the bits of the `double` it equals. - **Layout**: a `Float32` interpolation part is the text of its `Show` (`torb_show_f32`), not the `Float64` formatter. - **Constant folding** (`ir/constant.trb`, bytecode `emit.trb`): a `Float32` result is rounded to binary32 (via `std/binary/number`'s `float32Pattern`), so a folded constant has the bits the run time computes; an integer literal typed as a float now folds as a float (`const x: Float32 = 1 / 3` is `0.33333334`, not `0`). - **std/number**: `extend Float32 with TryFrom<Float64, NumberRangeError>`, the Float32 type doc and `Real` "# Open" updated. `std/encoding`'s Float32 comment updated. - **Docs**: LINEAR.md item 8, ROADMAP planned natives, RELEASE.md rows, BACKEND.md NativeState/gap 18, number.md (declarations + prose), binary.md, BINARY.md; skills/ references mirrored. Seed rule: new natives only, one commit; nothing in `std/` or the compiler uses them (the migration of `std/binary` is #349, `bits()`/`ofBits` #348). Not changed: the checker's own constant evaluator (`semantics/checker/constant.trb`) still computes a `Float32` constant in `Float64`; it only feeds diagnostics. ## Test - New conformance program `tests/conformance/float32.trb`: the 32-vs-64-bit sum, 2^24+1 / 2^24+3 rounding, `%`, negation, `absolute`, overflow to inf, subnormals, signed zero, nan comparisons and `compare`, the parse/show round trip, narrowing at the edges (halfway to 2^128, 3.5e38, 1e-50, nan/inf), and constant folding equal to the run time. Expectations computed with binary32 rounding outside the toolchain. - `floats.trb`: the Float32 line now also shows the named constants. - Runtime C tests for `torb_show_f32`/`torb_parse_f32` and `torb_convert_f64_f32_checked`. - No local toolchain build (machine load); all gates ran in this PR's CI and are green (tier A, tier B with the conformance suite native and in the VM). Allocation budgets from the CI report: `float32` 82 blocks, `floats` 28 -> 34 (its new line shows the five named Float32 constants). Closes #35
feat(runtime,backend): Float32 arithmetic, compare, Show and narrowing from Float64
Some checks failed
ci / commit messages (pull_request) Successful in 10s
ci / what the change touches (pull_request) Successful in 9s
pdisc / pdisc (pull_request) Successful in 12s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 11s
ci / bootstrap (linux-x64) (pull_request) Successful in 1m56s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Failing after 4m42s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m51s
ci / gates (pull_request) Has been cancelled
ci / the playground (torb as WebAssembly) (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
ci / every host emits the same C (pull_request) Has been cancelled
ci / tier B (linux-x64) (pull_request) Has been cancelled
a8d3d8b9c9
Float32 `+ - * / %`, unary `-`, `absolute()`, `==`, `<` and `compare` are ready
in the C back end and in the VM, every result rounded to binary32.
`torb_parse_f32` reads a Float64 and rounds it once, `torb_show_f32` writes the
shortest text that reads back to the same Float32, and
`Float32 with TryFrom<Float64, NumberRangeError>` (`torb_convert_f64_f32_checked`)
rounds to nearest even, passes nan and the infinities through and fails only for
a finite value that would round to an infinity.

Constant folding rounds a Float32 result the way the run time does, and an
integer literal typed as a float folds as a float. New natives only: nothing in
std or the compiler uses them yet (seed rule of #35).

Refs #35
orion force-pushed loop/35-float32-arithmetic from a8d3d8b9c9
Some checks failed
ci / commit messages (pull_request) Successful in 10s
ci / what the change touches (pull_request) Successful in 9s
pdisc / pdisc (pull_request) Successful in 12s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 11s
ci / bootstrap (linux-x64) (pull_request) Successful in 1m56s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Failing after 4m42s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m51s
ci / gates (pull_request) Has been cancelled
ci / the playground (torb as WebAssembly) (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
ci / every host emits the same C (pull_request) Has been cancelled
ci / tier B (linux-x64) (pull_request) Has been cancelled
to 029dd21400
Some checks failed
ci / commit messages (pull_request) Successful in 14s
ci / what the change touches (pull_request) Successful in 14s
pdisc / pdisc (pull_request) Successful in 14s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 19s
ci / bootstrap (linux-x64) (pull_request) Successful in 2m2s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Successful in 4m26s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m56s
ci / tier B (linux-x64) (pull_request) Failing after 10m15s
ci / pack the seed (pull_request) Has been skipped
ci / every host emits the same C (pull_request) Successful in 4m33s
ci / gates (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
ci / the playground (torb as WebAssembly) (pull_request) Has been cancelled
2026-10-12 21:57:45 +00:00
Compare
orion force-pushed loop/35-float32-arithmetic from 029dd21400
Some checks failed
ci / commit messages (pull_request) Successful in 14s
ci / what the change touches (pull_request) Successful in 14s
pdisc / pdisc (pull_request) Successful in 14s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 19s
ci / bootstrap (linux-x64) (pull_request) Successful in 2m2s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Successful in 4m26s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m56s
ci / tier B (linux-x64) (pull_request) Failing after 10m15s
ci / pack the seed (pull_request) Has been skipped
ci / every host emits the same C (pull_request) Successful in 4m33s
ci / gates (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
ci / the playground (torb as WebAssembly) (pull_request) Has been cancelled
to 9772502a4f
Some checks failed
ci / commit messages (pull_request) Has been cancelled
ci / what the change touches (pull_request) Has been cancelled
ci / gates (pull_request) Has been cancelled
pdisc / pdisc (pull_request) Has been cancelled
2026-10-12 22:12:15 +00:00
Compare
orion force-pushed loop/35-float32-arithmetic from 9772502a4f
Some checks failed
ci / commit messages (pull_request) Has been cancelled
ci / what the change touches (pull_request) Has been cancelled
ci / gates (pull_request) Has been cancelled
pdisc / pdisc (pull_request) Has been cancelled
to c6bd203180
Some checks failed
ci / commit messages (pull_request) Successful in 11s
ci / what the change touches (pull_request) Successful in 12s
pdisc / pdisc (pull_request) Successful in 11s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / which runners exist (pull_request) Successful in 1s
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 14s
ci / bootstrap (linux-x64) (pull_request) Successful in 1m59s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Successful in 4m32s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 2m9s
ci / every host emits the same C (pull_request) Successful in 4m37s
ci / tier B (linux-x64) (pull_request) Successful in 11m43s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m52s
ci / gates (pull_request) Successful in 0s
images / cr.torb.dev/torbscript/registry (push) Has been skipped
images / cr.torb.dev/torbscript/release-sync (push) Has been skipped
images / cr.torb.dev/torbscript/site (push) Has been skipped
ci / commit messages (push) Successful in 11s
ci / what the change touches (push) Successful in 15s
ci / gates (push) Has been cancelled
pdisc / pdisc (push) Has been cancelled
images / cr.torb.dev/torbscript/site:edge (main) (push) Has been cancelled
2026-10-12 22:12:26 +00:00
Compare
argus approved these changes 2026-10-12 22:54:50 +00:00
argus left a comment

Approved. Checklist (head c6bd203):

  • Tests: ok. New conformance program float32.trb (both back ends via CI tier A/B, allocation budgets set), floats.trb extended, C runtime tests for torb_show_f32/torb_parse_f32/torb_convert_f64_f32_checked, manifest test updated. CI combined status success on this head (skipped jobs are the other-OS runners).
  • Correctness: ok. Narrowing threshold 0x1.ffffffp127 is the exact halfway point to 2^128 and ties to even go to infinity, so >= is right; torb_parse_f32 uses the same cut-off. Show/parse round trip is consistent because both read through strtod then (float). The float * out-parameter via a temporary matches the register representation. Folding rounds each result to binary32; double rounding is innocuous for + - * / at 53 >= 2*24+2 bits, so folded constants match the run time.
  • Scope: ok. Matches all acceptance criteria of #35 slice 1; Real for Float32 and std/binary migration stay out.
  • Security/data: nothing relevant. Docs, skills mirrors and std doc comments updated.

Non-blocking:

  • [suggestion] The doc comment on floatingValue says + - * / of two Float32 are "exact in a Float64"; for +/- with widely different exponents that is not exact, only correctly rounded after the second rounding. Wording only.
  • [suggestion] An integer literal above 2^53 typed as Float32 is rounded twice in the compiler (Int to double to float) where C converts it directly; this can differ in the last bit for such literals. Worth a conformance case or a direct path in a follow-up.
Approved. Checklist (head c6bd203): - Tests: ok. New conformance program `float32.trb` (both back ends via CI tier A/B, allocation budgets set), `floats.trb` extended, C runtime tests for `torb_show_f32`/`torb_parse_f32`/`torb_convert_f64_f32_checked`, manifest test updated. CI combined status success on this head (skipped jobs are the other-OS runners). - Correctness: ok. Narrowing threshold `0x1.ffffffp127` is the exact halfway point to 2^128 and ties to even go to infinity, so `>=` is right; `torb_parse_f32` uses the same cut-off. Show/parse round trip is consistent because both read through `strtod` then `(float)`. The `float *` out-parameter via a temporary matches the register representation. Folding rounds each result to binary32; double rounding is innocuous for `+ - * /` at 53 >= 2*24+2 bits, so folded constants match the run time. - Scope: ok. Matches all acceptance criteria of #35 slice 1; `Real` for Float32 and `std/binary` migration stay out. - Security/data: nothing relevant. Docs, skills mirrors and std doc comments updated. Non-blocking: - [suggestion] The doc comment on `floatingValue` says `+ - * /` of two Float32 are "exact in a Float64"; for `+`/`-` with widely different exponents that is not exact, only correctly rounded after the second rounding. Wording only. - [suggestion] An integer literal above 2^53 typed as `Float32` is rounded twice in the compiler (Int to double to float) where C converts it directly; this can differ in the last bit for such literals. Worth a conformance case or a direct path in a follow-up.
argus merged commit c6bd203180 into main 2026-10-12 22:54:51 +00:00
argus deleted branch loop/35-float32-arithmetic 2026-10-12 22:54:52 +00:00
Sign in to join this conversation.
No reviewers
No labels
loop
ready
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language!352
No description provided.