Repository navigation
Own backend, step 4: numbers - #43
Merged
Merged
Conversation
a * b of two values, a / b and a % b of two values and by a constant, signed and u32, written where they are used. A product tests its narrower side a bit at a time and adds the other side: its multiples as fields of their own when the tested side is narrow (a trigger a bit), else Horner's way, the product doubling in one action of a trigger that walks a run of bit triggers by moving its own next pointer on. A quotient by a constant is eudplib's chain inlined, as long as the ranges allow; of two values, long division with the remainder doubling and one shared step holding the divisor in two fields. Operands the plan copies are routed into a routine's fields where it starts, never kept as multiples. Fills fold their scratch cell's conditions and routes too; copies into multiples go over only the bits a range allows. probes/own-numbers.ts, lifted game: 200 products 0.700 ms against eudplib's 0.943; by constants 0.572 / 0.730; quotients 0.848 / 1.175; remainders 0.750 / 1.148; small numbers 0.514 / 0.764. Ledger: step 4, 17 of 59. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1CM9pLuTuAn3mgTEkjgVg
& | ^ as values, with a constant and of two values, are masked writes of a copy: the game works a masked write on the bits under its mask alone, an addition's carry past it lost, so & and | are one write whose mask is the other side (an action's mask is a field like any number, flipped for & by two masked additions of all ones), and ^ two masked additions over the even and the odd bits. A shift left by a value walks a doubling trigger through runs of empty triggers, one a bit of the count; a shift right is Horner's way over the bits that stay, the doubling trigger counting. Counts of 32 or more leave nothing (or the sign), as TrigScript has it; the existing << by a constant took the remainder, and >> 0 is the number itself. A scratch value read by one field only is worked in that field. The tests' interpreters do masked writes as the game does. probes/own-bits.ts, lifted game: masks 0.063 ms against eudplib's 0.146; bits of two values 0.086 / 0.217; shifts by a value 0.834 / 2.399. Products and quotients moved to 1.4–1.6x with the fill into one field. Ledger: step 4, 27 of 59. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1CM9pLuTuAn3mgTEkjgVg
Fixed (16.16) products and quotients by a constant and of two values, a constant over a value, and a fixed number printed, each faster than the eudplib build in the lifted game (x*y 0.52 vs 0.68 ms for 200, x/y 0.69 vs 1.09, nine printed 0.015 vs 0.17). random(n) and random() draw the game's own random bits through Set Switch to a random state and draw again past the bound, so every number below n is as likely; 200 draws below a value cost 0.26 ms against eudplib's 1.84. An index that is more than a sum is worked out first, which takes pick(list) and step 3's last row, xs[a >> 1]. Ledger: step 3 54 of 54, step 4 44 of 59 (left: sqrt, sin, cos, atan2, u8, u16). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1CM9pLuTuAn3mgTEkjgVg
…d u16 Step 4 is done: the ledger's 59 rows of numbers are all taken by a map of our own. A square root keeps the root at the place its bits end up, so it only gains constants, and doubles the remainder instead; a shared compare trigger steps its own next pointer into a pair of triggers laid out for each step. Sines, cosines and arc tangents are written as statements the emitter already makes, and the arc tangent's quotient takes 17 steps, not 47. Stores into u8 and u16 stop at their top. In the lifted game, 200 of each against the eudplib build: sqrt 0.39 vs 1.35 ms, of a whole number 0.65 vs 3.67, sin and cos 1.09 vs 2.26, atan2 1.34 vs 2.30. Also fixed: a whole number's square root below zero had the value range 0, so comparing it was worked out wrong when the map was built, in both builds; and a shift whose count comes to a constant was refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1CM9pLuTuAn3mgTEkjgVg
CI timed out on #43: the random programs with functions took 130 s there and the ones on a stack 283 s, past the 120 s allowed, once step 4 put products, quotients, square roots and sines in them (a program of twenty of them is thousands of triggers to lay out and walk). A program now holds four at most; each kind still comes in thousands of programs. Here they take 23 s and 47 s (12 s and 25 s before step 4), about three times that on CI, so the limit is 300 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1CM9pLuTuAn3mgTEkjgVg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 4 of the way off eudplib: every number a program works with, in a map of our own. All 59 of the ledger's number rows are taken. Each part has its own section in
docs/v4-plan.md.Follows #42 (merged first; this PR was stacked on it).
No other row changed.
What it adds
u32. A product adds one side Horner's way in a doubling trigger. A division doubles the remainder, with one shared step holding the divisor.&|^as values, and shifts by a value. Bits are masked writes: an action's mask field holds the other side, as eudplib does it, without the calls. Shift counts of 32 or more saturate, as TrigScript has it.random(n)andrandom()draw the game's own random bits through Set Switch to a random state. A draw that comes out at n or more is made again, so every number below n is exactly as likely. eudplib'sf_dwrand % nleans slightly towards small numbers.Math.sqrt,sin,cos,atan2, andu8/u16.u8andu16stop at their top.Measured
Each probe was built both ways and played in the lifted 1.16.1 game, weighed with Remastered's costs. Every line printed is the same both ways and ends "ok". Times are for 200 of each:
&|^of two valuesx * yx / yrandom(j % 10 + 1)Math.sqrt(x), x fixedMath.sqrt(n), n wholeMath.sin/Math.cosMath.atan2The probes are
probes/own-numbers.ts,own-bits.ts,own-fixed.ts,own-random.tsandown-math.ts.Fixed on the way, in both builds
Math.sqrt(w) == …was then worked out wrong when the map was built (compiler/ranges.ts; test intests/fixed.test.ts).Fixed on the way, in our own build
x << ktook the count's remainder.a >> 0and a shift whose count always works out to the same number were refused; both are now taken.xs[a >> 1], the last refused row of step 3, is now taken.Checked
Left for later (in the plan)
own-math.tsis 9 MB. A routine shared by every use, as the digits routine is, is the fix.🤖 Generated with Claude Code
https://claude.ai/code/session_01T1CM9pLuTuAn3mgTEkjgVg