|
| 1 | +# Single-Limb Raw-Ratio Performance Design |
| 2 | + |
| 3 | +**Date:** 2026-08-01 |
| 4 | +**Status:** Complete — specialization accepted |
| 5 | +**Repository:** `FixedMathSharp` |
| 6 | + |
| 7 | +## Problem |
| 8 | + |
| 9 | +The benchmark backlog records an incomplete performance signal for |
| 10 | +`Fixed64.TryGetSignedRawRatio(Signed576, Signed576, ...)` when the denominator |
| 11 | +has one active 64-bit limb. The original investigation was terminated without |
| 12 | +a completed timing sample and predates the overload's current `Signed192` and |
| 13 | +`Signed320` narrowing paths. |
| 14 | + |
| 15 | +The shared divider still routes a one-limb denominator through equal-length |
| 16 | +multi-limb shift, compare, subtract, and midpoint work. That shape is a |
| 17 | +plausible bottleneck, but production specialization is not justified until a |
| 18 | +current isolated benchmark proves it. |
| 19 | + |
| 20 | +## Goals |
| 21 | + |
| 22 | +- Produce a stable current baseline for representative one-limb denominators. |
| 23 | +- Compare those rows with a multi-limb denominator control. |
| 24 | +- Specialize only if the measured cost is material. |
| 25 | +- Preserve the complete arbitrary signed wide-ratio contract: denominator and |
| 26 | + numerator signs, zero handling, round-half-to-even, signed raw range, and |
| 27 | + honest rejection of unrepresentable results. |
| 28 | +- Preserve deterministic behavior, zero allocation, `netstandard2.1` |
| 29 | + compatibility, and one portable implementation across target frameworks. |
| 30 | +- Retain a focused benchmark guard and close the backlog with measured evidence. |
| 31 | + |
| 32 | +## Non-Goals |
| 33 | + |
| 34 | +- Do not change any public API or rounding contract. |
| 35 | +- Do not assume the denominator is positive or that the quotient is |
| 36 | + representable. |
| 37 | +- Do not replace the general multi-limb divider. |
| 38 | +- Do not add `UInt128` or another target-specific implementation without a |
| 39 | + separate benchmark proving the portable `Divide128By64` helper is the |
| 40 | + remaining bottleneck. |
| 41 | +- Do not optimize unrelated wide-arithmetic paths. |
| 42 | + |
| 43 | +## Benchmark Design |
| 44 | + |
| 45 | +Add one dedicated `WideRawRatioBenchmarks` fixture with deterministic values |
| 46 | +covering: |
| 47 | + |
| 48 | +1. A one-word numerator and one-word denominator. |
| 49 | +2. A two-word numerator and 32-bit denominator. |
| 50 | +3. A two-word numerator and 64-bit denominator. |
| 51 | +4. A one-word denominator whose quotient is immediately unrepresentable. |
| 52 | +5. A multi-word denominator control that remains on the general divider. |
| 53 | + |
| 54 | +Every row calls the production `Signed576 / Signed576` contract and reports |
| 55 | +managed allocation. Capture the baseline and candidate with the same Release |
| 56 | +build, BenchmarkDotNet job, machine, filters, and artifact layout. |
| 57 | + |
| 58 | +The specialization is accepted only when a stable out-of-process comparison |
| 59 | +shows at least a provisional 15% improvement in the affected representable |
| 60 | +rows, zero managed allocation, and no multi-limb control regression beyond 5% |
| 61 | +or ordinary run noise. If the baseline is already competitive, retain the |
| 62 | +benchmark and close the signal with a no-change decision. |
| 63 | + |
| 64 | +## Conditional Production Design |
| 65 | + |
| 66 | +If the evidence gate opens, specialize the shared |
| 67 | +`TryGetSignedRawRatioCore(...)` boundary when the active denominator length is |
| 68 | +one. The numerator can contain at most two active limbs when its quotient fits |
| 69 | +in 64 bits; larger magnitudes are rejected before division. Reuse the existing |
| 70 | +portable `Divide128By64(...)` helper, compare the remainder with |
| 71 | +`denominator - remainder` for overflow-free half-even classification, and |
| 72 | +delegate final rounding, signed-range validation, and materialization to the |
| 73 | +existing `TryCreateRawRatioResult(...)` owner. |
| 74 | + |
| 75 | +This location serves `Signed576`, `Signed704`, `Signed832`, and span-backed |
| 76 | +callers without duplicating representation mechanics in an overload-specific |
| 77 | +fast path. Multi-limb denominators continue through the current fixed-limb |
| 78 | +divider unchanged. |
| 79 | + |
| 80 | +## Correctness And Test Design |
| 81 | + |
| 82 | +The optimization is behavior-preserving, so its RED evidence is the completed |
| 83 | +benchmark showing the current path misses the approved performance gate rather |
| 84 | +than an artificial unit-test failure. Existing wide-ratio tests remain the |
| 85 | +contract baseline. Before production changes, extend the `BigInteger` oracle |
| 86 | +matrix only where needed to pin: |
| 87 | + |
| 88 | +- positive and negative numerator/denominator combinations; |
| 89 | +- below-half, exact even/odd midpoint, and above-half rounding; |
| 90 | +- one- and two-limb numerators; |
| 91 | +- `long.MaxValue` and `long.MinValue` materialization boundaries; |
| 92 | +- quotient overflow before rounding and overflow caused by rounding; and |
| 93 | +- equivalence between single-limb and general denominator results. |
| 94 | + |
| 95 | +No test-only production hook, path counter, reflection check, or benchmark |
| 96 | +timing assertion belongs in the unit suite. |
| 97 | + |
| 98 | +## Verification And Closure |
| 99 | + |
| 100 | +- Re-run the exact baseline benchmark after each candidate change. |
| 101 | +- Run focused wide-arithmetic tests, then complete `Release` and `ReleaseLean` |
| 102 | + suites. |
| 103 | +- Preserve 100% reachable line, branch, and method coverage. |
| 104 | +- Build standard and Lean packages for both target frameworks with zero |
| 105 | + warnings. |
| 106 | +- Re-run downstream Gravitas gates only if the internal ABI or a consumed path |
| 107 | + changes materially. |
| 108 | +- Request independent correctness and performance review before closure. |
| 109 | +- Move the backlog entry to Closed Signals with the baseline, final evidence, |
| 110 | + and either the accepted specialization or explicit no-change decision. |
| 111 | +- Leave all changes unstaged and uncommitted for repository-owner review. |
| 112 | + |
| 113 | +## Final Outcome |
| 114 | + |
| 115 | +The shared one-limb-denominator specialization was accepted. Canonical |
| 116 | +BenchmarkDotNet `DefaultJob` artifacts compare base `28aef44` with the final |
| 117 | +candidate under the same Release/net8.0 environment: |
| 118 | + |
| 119 | +| Row | Baseline mean | Candidate mean | Mean delta | Baseline median | Candidate median | Median delta | Allocated | |
| 120 | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | |
| 121 | +| One-word numerator/denominator | 160.759 ns | 51.770 ns | -67.80% | 160.561 ns | 51.676 ns | -67.82% | 0 B -> 0 B | |
| 122 | +| Two-word numerator / 32-bit denominator | 279.194 ns | 61.077 ns | -78.12% | 277.527 ns | 60.916 ns | -78.05% | 0 B -> 0 B | |
| 123 | +| Two-word numerator / 64-bit denominator | 376.112 ns | 131.217 ns | -65.11% | 374.211 ns | 131.199 ns | -64.94% | 0 B -> 0 B | |
| 124 | +| Unrepresentable quotient | 42.586 ns | 43.207 ns | +1.46% | 42.568 ns | 43.174 ns | +1.43% | 0 B -> 0 B | |
| 125 | +| Multi-word denominator control | 73.190 ns | 72.257 ns | -1.27% | 72.626 ns | 71.670 ns | -1.32% | 0 B -> 0 B | |
| 126 | + |
| 127 | +All three affected representable rows exceed the 15% improvement gate on mean |
| 128 | +and median. The multi-word control stays within the 5% regression gate by |
| 129 | +improving 1.27% by mean and 1.32% by median. Every row remains allocation-free, |
| 130 | +the public/general-divider contracts are unchanged, and final Release, |
| 131 | +ReleaseLean, coverage, package, downstream, and independent-review gates pass. |
| 132 | +Canonical artifacts are preserved under |
| 133 | +`artifacts/benchmarks/2026-08-02-single-limb-raw-ratio-canonical-baseline/` and |
| 134 | +`artifacts/benchmarks/2026-08-02-single-limb-raw-ratio-canonical-candidate/`. |
0 commit comments