Drop a multiply to the step below rather than rounding it
Bryan's call, 2026-09-16, taken for the cycles: a share now lands a thousandth of a pixel short of its row instead of on it, which is less than an even number of pixels draws. `Fixed::mul` is a widening multiply and a shift, with the sign branch and the half-step add gone. The two short-circuits priced against the old multiply go with it: `UiSpan::within`'s test for a span that is the whole of its parent, and `Fixed::scaled`'s test for nothing scaled by something, which was the whole of `scaled` -- both cases come out of the truncating multiply unchanged, and the bodies the comparisons cost were what kept the inliner from taking `within` at all. `nm` is the check: `<UiSpan>::within` is a symbol in the rounding head and in neither the float head nor this one. `Holds::through` inverts the multiply, so its widening is re-derived: each rounding now drops a whole step where it dropped half of one, which doubles the allowance for the two routes to a length, and the multiply on the way in drops only downward, so its own step goes at the top of the range alone. The derived allowance for one truncation either side is measurably too narrow -- it excludes boxes drawings were made in, in eleven generated cases -- because each route is a chain of multiplies rather than one. Measured on the fixed-shape fixture (`Edits::fixed_branches`), seed 1 depth 8, 500 frames of `many`, medians of 25 runs of uninstrumented release binaries with this VM's garbage `perf` readings dropped: | | instructions | cycles | IPC | | --- | ---: | ---: | ---: | | `5ed9e87`, the float head | 1,761M | 688M | 2.561 | | `60367d8`, rounding | 1,915M | 777M | 2.465 | | this | 1,800M | 715M | 2.516 | -6.0% instructions and -8.0% cycles against `60367d8`, whose twenty-five work counters are identical to this one's, so that pair is the same work at a different speed. It leaves +2.2% and +3.9% against the float head, from +8.7% and +12.9% -- but the float head draws 100 widgets to this one's 97 and writes 4,272 primitives to 3,951, so that pair is not, and the remainder is not all arithmetic. Checked: fmt, clippy, 80 suite tests and 18 core unit tests, the release oracle at 100 seeds, all fifteen shrinker cases at 400 seeds of depth 5 (seed 288 on `region-node` still failing, unchanged), and depth-6 oracle seeds 18 and 190 passing with 326 still failing. `view`, `minimal`, `text`, `random` and the tab replay render byte-identical at 1920x1200; `tabs` differs on 4,664 of 2,304,000 pixels, single-pixel-wide runs along 80 columns of one band of rounded rects, which is an antialiased edge moved less than a pixel. Three tests say what changed rather than being relaxed: a multiply drops on both sides of zero, a division cannot put back what it dropped, and an unevenly nested row's shares stay contiguous and end at its edge with each edge on the even division or one step below. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
60367d806e
commit
08c9d5aa32
5 files changed
+101
-73
No files matched your search
+21
-2
@@ -266,6 +266,11 @@ fn nested_spans_divide_the_space_once_however_deep_the_nesting_is() {
|
||||
|
||||
/// The same space, unevenly nested: weights carried up mean a share is a
|
||||
/// share of the whole, not of whatever branch a widget happens to sit in.
|
||||
///
|
||||
/// Each edge lands on the even division or one step below it, since a share
|
||||
/// is a fraction of the room and a truncating multiply gives up what that
|
||||
/// fraction does not divide. What stays exact is that each share starts
|
||||
/// where the last one ended and the row ends at its own edge.
|
||||
#[test]
|
||||
fn an_uneven_nesting_still_gives_every_share_the_same_length() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
@@ -279,10 +284,24 @@ fn an_uneven_nesting_still_gives_every_share_the_same_length() {
|
||||
let three = (b, c, d).span(Dir::RIGHT).add(&mut h.rsc);
|
||||
h.set_root((one, three).span(Dir::RIGHT));
|
||||
|
||||
let mut start = Px::ZERO;
|
||||
for (i, id) in [a, b, c, d].into_iter().enumerate() {
|
||||
let x = i as f32 * 100.0;
|
||||
assert_corners!(h, id, (x, 0), (x + 100.0, 200));
|
||||
let got = h.region(&id).expect("widget drew nothing");
|
||||
let even = Px::from_int((i as i32 + 1) * 100);
|
||||
assert_eq!(got.top_left, PxVec2::new(start, Px::ZERO), "share {i}");
|
||||
assert_eq!(got.bot_right.y, Px::from_int(200), "share {i}");
|
||||
assert!(
|
||||
got.bot_right.x == even || got.bot_right.x == even.next_down(),
|
||||
"share {i} ends at {:?}, not {even:?}",
|
||||
got.bot_right.x
|
||||
);
|
||||
start = got.bot_right.x;
|
||||
}
|
||||
assert_eq!(
|
||||
start,
|
||||
Px::from_int(400),
|
||||
"the row stopped short of its edge"
|
||||
);
|
||||
}
|
||||
|
||||
/// However many ways a row is divided, the shares add up to the row: each
|
||||
|
||||
Reference in new issue
Block a user