binary: read and write floats through bits()/ofBits(_), float32() answers a Float32 #349
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
With slices 1 and 2 built,
std/binarycan drop its TorbScript bit arithmetic. This is slice 3 of theFloat32work and the last one.Source
Acceptance criteria
ByteReader.float32()answersResult<Float32, ReadError>;float64()keepsFloat64. Both keep anan's payload (ofBits), soread(write(x))has the bits ofxfor every pattern.ByteWriter.float32takes aFloat32(aFloat64is narrowed by the caller,Float32.tryFrom; the writer keeps no rounding code of its own),float64writesbits().std/binary/src/number.trblosesfloat32Pattern,float32OfPattern,float64Pattern,float64OfPatternand their helpers; users inside the repo (std/digest,std/dns,std/archive, ... whichever callfloat32()/float64()) are migrated in the same change.std/binaryfloat tests keep passing with the new types; a new test reads and writesnanpayloads; a benchmark or measurement note of the old and new read of 1Mfloat64().docs/design/BINARY.mddecision 3 and section 10 rewritten, thestd/binaryreference regenerated inskills/.Design record point
BINARY.md section 10, decision 3.
Seed impact
No new native, but the change uses natives of slices 1 and 2 from
std, which the compiler of the seed must know: the second commit of the two-commit rule ("teach both forms, refresh the seed, then migrate"). It lands only after the seed was refreshed from amainthat contains slices 1 and 2.Dependencies
Blocked by slice 2 and by the seed refresh after it (Torben's,
tools/refresh-seed.sh). Notreadyuntil then.Float64.bits(),ofBits(_)and the same forFloat32Float32arithmetic, comparison, text and narrowing fromFloat64(slice 1) #35[loop:torbscript] decided by the loop: slice 3 of #35.
ByteWriter.float32takes aFloat32and the caller narrows withFloat32.tryFrom, so the writer keeps no rounding code; the oldFloat64-typedfloat32()result changes toFloat32as BINARY.md section 10 planned, before 1.0. Notready: needs #348 merged and the seed refreshed (Torben'stools/refresh-seed.sh) under the two-commit rule. next: waiting (blocked by #348 and the seed refresh)Float32arithmetic, comparison, text and narrowing fromFloat64(slice 1) #35[loop:torbscript] claim refine by session:loop-torbscript-20261024 until 2026-10-24T03:00Z
[loop:torbscript] decided by the loop: the blocker is gone and three points of the acceptance criteria are corrected as follows (the issue body stays as written; this comment is the amendment).
Blocker. Slices 1 and 2 are on
main(#35 via PR #352, #348 viad37b931e), and the seed that CI bootstraps from already knows them: the published seed40164061bd10(releaseseeds, newest inseeds.txt, 2026-10-23) descends fromd37b931e. CI and fresh clones bootstrap withtools/fetch-seed.sh, so Torben's localtools/refresh-seed.shis not needed for this change. Second commit of the two-commit rule: allowed now.1. A user the issue did not list.
compiler/src/ir/constant.trbimportsfloat32Pattern,float32OfPatternfromstd/binary/number(roundedToFloat32, line ~602). Nostd/digest,std/dnsorstd/archivecode callsfloat32()/float64(); the only users arestd/binaryitself and that function. Migrate it in the same change:roundedToFloat32answersFloat64.from(Float32.tryFrom(value))for anOk, and the infinity of the value's sign for aNumberRangeError, so a literal beyond3.4e38still folds to an infinity as today. Then theuse ... from "std/binary/number"goes.2. Range failure of the narrowing.
Float32.tryFrom(Float64)fails withNumberRangeErrorwhen a finite value rounds to an infinity (std/numberdoc), where the oldByteWriter.float32wrote7f800000. The writer takes aFloat32and keeps no rounding code, so the caller decides: the test "binary32 is the nearest value" (std/binary/tests/writer.test.trb,1.0e39) narrows withFloat32.tryFrom(1.0e39) ?? Float32.infinity-style handling in the test helper and still expects7f 80 00 00.BINARY.mddecision 3 states that the failure is the caller's, with that one-line idiom. No wrapper in the package.3. Shape of the change.
ByteReader.float32answersResult<Float32, ReadError>:Float32.ofBits(word32(unsigned(4, ...)?));float64answersFloat64.ofBits(unsignedOf(pattern64(...)?)). Both keep everynanpayload.ByteWriter.float32(value: Float32, ...):put(Int.from(value.bits()), 4, ...);float64:put(patternOf(value.bits()), 8, ...).number.trbdrops the fourfloat*Pattern/float*OfPatternfunctions andpowerOfTwo,scaled,normalized,isNegative,wholeOf,roundedEven(check each has no other caller); the header comment loses the float sentence.reader.float32()assertions compare againstFloat32literals; the existingnan/-0.0/infinity cases stay; new test: for thenanpatterns7fc00001,7f800001(signalling),ffc12345and the 64-bit7ff0000000000001,fff8dead0000beef,read(write(x)).bits() == x.bits().benchmarks/(asbinary-formats.trbis) that reads 1Mfloat64()from aBytes; the PR body carries the seconds ofmainand of the branch from the forge'sbenchmarksworkflow. Measure first, no budget set up front; it is a measurement, not a gate (benchmarks/README).BINARY.mddecision 3 and section 10 rewritten (the "Open" item forFloat32leaves; section 2's statement that the package uses no native is corrected), thestd/binarypage regenerated intoskills/.Seed impact. No new native, no syntax change, no std name looked up by string by the compiler. The compiler source itself now uses
Float32.tryFrom/Float64.from(inconstant.trb), which the seed40164061bd10compiles. The worker must confirm in CI that the bootstrap fixpoint holds. Size: one PR, two Conventional Commits at most (feat(std/binary): ...for the code,docs(std/binary): ...for BINARY.md andskills/).[loop:torbscript] refine: ready, claim released, next: implement
Dependencies #35 and #348 are merged and the published seed
40164061bd10knows both, so the issue meets the Definition of ready (see the decision comment above for the corrected acceptance criteria: thecompiler/src/ir/constant.trbuser, the caller-side handling ofNumberRangeError, the shape of the change). Labelreadyset. Touches the seed: no (second commit of the two-commit rule, the first landed with #348). Worker: refine worker (sonnet, read-only, repo atmain7d4fe624), about 70k tokens by estimate, exact count not visible to the worker.[loop:torbscript] claim implement by session:loop-torbscript-20261024 until 2026-10-24T05:30Z
[loop:torbscript] release implement: the implement worker hit its run timeout without a result comment after opening PR #447; forge CI pending. next: waiting (CI running on PR #447)