Generate plain long-double and experimental FMA variants from the production entry kernel. Compare exact-rational references, geometric validation, fallback counts and repeated timings with self-contained fixtures. Validate cached build dependencies and reject stale timing output. Count all unconfirmed entry outcomes independently of reference classification.
11 KiB
quadratic_precision — stable entry quadratic: precision vs. cost
Self-contained, reproducible benchmark comparing four arithmetic realisations of
the same asymptotic-entry algebra. Nothing here modifies production code,
the Makefile, or git state.
Question
The production camera pre-route solves the relative-distance quadratic
F(s) = |d + q s|^2 - (R0 - rr s)^2 = a s^2 + b s + c
d = x_cur - c_frame, q = w_frame + v_frame
in long double, with a stable root formula, an ordinary discriminant
b*b - 4*a*c and entry slope, a common power-of-two scaling, an
uncertainty band, geometric validation and a numerical fallback. Which matters
for accuracy and which for speed?
Four variants share the entire rest of the module (scaling, uncertainty band,
validation, fallback, dispatch) and are generated from the current
src/asymptotic.c by rewriting exactly one lexical region:
| variant | coefficients | type | discriminant / slope |
|---|---|---|---|
ld_plain |
as production | long double |
plain b*b - 4*a*c, plain slope |
ld_fma |
as production | long double |
compensated fmal (experimental arm) |
double_fma |
ordinary += |
double |
compensated fma |
double_fma_coeff |
fma dots, fma products |
double |
compensated fma |
double_fma is the control that isolates type precision from FMA; the two
double variants isolate coefficient accumulation.
Generation and build
build.py locates the kernel region between two lexical anchors in the current
working-tree src/asymptotic.c:
- start: the comment
/* Long-double coefficients of the relative-distance quadratic - end: the forward declaration
static void minkowski_route_entry(...)
It asserts each anchor and the presence of entry_quadratic_coeffs,
entry_solve, entry_discriminant exactly once, then emits four full-module
copies under <output>/generated/. Every other line (dispatch, fallback,
asymptotic_route_camera, Schwarzschild path, …) is copied verbatim. If a
future edit moves an anchor or changes the region, generation fails rather
than silently measuring the wrong code.
ld_plain retains the production kernel verbatim; ld_fma rewrites only the
discriminant body and the entry slope. Double
variants replace long double→double, fmal/fabsl/fmaxl/frexpl/
scalbnl/sqrtl/copysignl→their double forms, LDBL_*→DBL_*, and strip
L suffixes from literals. A guard rejects any remaining long double
promotion, L literal or *l/fmal call in the double kernel section, so no
double expression can be re-promoted to long double. double_fma_coeff
additionally changes the coefficient accumulation to fma.
The probe #includes the generated module, so the private static
entry_quadratic_coeffs/entry_solve and the public asymptotic_route_camera
that are exercised are the actual generated code, not an independent copy.
Compile flags, identical for all four variants:
-std=c11 -march=native -O2 -DNDEBUG -ffp-contract=off -fopenmp
-ffp-contract=off prevents implicit FMA contraction from silently changing
the ld_plain arm; explicit fma/fmal still lower as written.
The probe links a minimal production subset (geodesic.c,
asymptotic_entry.c, asymptotic_schwarzschild.c, spacetime_common.c,
spacetime_minkowski.c) plus libm. No FFTW, PNG, catalog or observer-track
data are needed.
Inputs
All fixtures are frozen as IEEE-754 hex literals (cases.json and the
generated C header are bit-identical), including the two production grazing
rows reproduced from the Alcubierre pre-route (x=(0,-24,0), centre=2t,
v=2, R=5, canonical w hex values). Families:
- curated / adversarial: head-on hit/miss, clear miss, grazing
y=nextafter(R,0), exact tangent, near-boundary,1e10 + 0.5, R=1cancellation, large-tcentre=0.1t, exact lineara==0(inward and initially outward), translated-origin cancellation. - fixed: axes and three oblique frames, radii
1e-100…1e100,D/R ∈ {1+ulp,2,10,100,512,1024,1e4,1e8,1e10}, impact ratios{0,.5,.99,1-1e-6,nextafter(1,0),1,nextafter(1,∞),1+1e-6,1.1}. The512/1024ratios sample the crossover where long-double coefficient rounding meets the128 ε_D R²geometry tolerance (≈512) and the double crossover (≈11), separating fallback rates from the all-UNCERTAIN1e10regime. - moving:
v ∈ {0,.1,2,10}along a transverse direction. - growing:
rr = -1andnextafter(-1,∓∞), inward and initially-outward photons (w = ∓tow), axis and oblique. - shrinking:
rr>0, labelled/domain-checked algebra (radius would go negative on the open past; roots outsideR0 - rr·s > 0are non-physical). - route:
rr = 0plusrr<0growing inward/outward families (positive radius on the whole past,valid_t_min=-1e300) across all three direction frames, driven through the publicasymptotic_route_camera. The oblique-2 growing-outward family reproduces the double kernel false-MISS cases, where a kernel MISS bypasses the fallback and the route escapes directly; the route reference uses the actual normalised canonicalw, so normalisation effects are explicit.
Exact counts are emitted by the run (and in summary.json); they are not
hard-coded here.
Reference oracle
Inputs are exact, so they are represented as fractions.Fraction (Python
stdlib). d, q, a, b, c, the discriminant and polynomial residuals
are exact rationals; only sqrt uses decimal (--precision, default
160). A custom hex parser handles both %a (double) and %La (long double)
without float.fromhex, which would silently drop a 64-bit long-double mantissa
to 53 bits. Reference classification mirrors production semantics: c<0 is
INSIDE (not an entry failure), c==0 uses the boundary slope, a==0 is the
exact linear branch, a real double root/tangent is MISS.
Route references are built from the actual canonical state the probe printed
(canonx*, canonw*) joined with the callback samples at t0, so the 1-ulp
normalisation of w and both callback models (centre = c0 + v(t-t0) and the
production centre = v t) are handled explicitly.
Metrics
Kernel:
- status counts (ENTRY/MISS/UNCERTAIN) vs the reference, false MISS (reference ENTER, kernel MISS) and false candidate (reference MISS, kernel ENTRY);
- root error in ULP of the returned double root and relative error, for the common reference-ENTER set and the intersection where all variants returned ENTRY (so more UNCERTAIN cannot look better by selection);
- polynomial residual at the candidate root using the actual printed coefficients, the exact ideal polynomial, and the nearest-double-rounded reference root as a baseline;
aexact-zero vs kernel-zero,asign mismatches,acollapse/spurious non-zero, and conditioning labels (near_linear,late,ill_conditioned). Outward/growing and near-linear cases are ill-conditioned; a rounded-zeroacan turn a very late true entry into a false MISS, so these are reported separately and are not treated as a universal precision claim.
Route:
- kind/status vs reference, false MISS, false candidate, camera-INSIDE
mismatches, total
INVALID/ENTRY_UNCONFIRMEDoutcomes independent of reference classification (a conservative refusal to confirm is not a false escape); - the public kernel classification at the actual canonical inputs
(
kern_statusin the route CSV), so a reference ENTER / kernel MISS / route ESCAPED (kernel_false_miss_escaped) is visible and is not confused with canonical normalisation; - fast-path vs fallback (
entry_fallback_evaluations),F/tolfor accepted entries, and Pi/L_camerapreservation.
The reference enforces R0 - rr·s > 0 for quadratic roots; a positive root
outside the physical radius domain is reported as domain_clipped and is not
counted as a physical ENTER/false-MISS. A 160-vs-240-digit consistency check is
run for every curated and near-linear/late/domain-clipped id and must report the
same status, discriminant sign and nearest-double root.
Timing:
- kernel: coefficient assembly +
entry_solve, serial,noinline+volatilesink, and an inline-asm opaque loop index so GCC cannot hoist the pure kernel out of the repetition loop (identical for all variants). A linearity check runs the kernel at 1× and 2× calls and reports the ratio (expect ≈2) to prove per-call execution. - route: public pre-route, OpenMP
staticschedule + reductions, with route-kind and fallback counts captured so a timing gain cannot come from silently escaping more rays.--threadsdefaults to 4.
Codegen evidence is collected with objdump/nm: for the double variants
entry_solve contains hardware vfmadd and zero x87; for ld_fma it contains
x87 plus fmal PLT relocations (extended-precision FMA is a libm software
routine on x86-64).
Run
python3 benchmarks/quadratic_precision/run.py \
--output-dir /tmp/opencode/quadratic-comparison
Useful overrides: --rounds N, --threads T, --precision P,
--kernel-target-calls N, --route-target-calls N, --skip-build (reuse the
last build), --repo PATH, --cc CC.
Artifacts (all under --output-dir):
generated/{ld_plain,ld_fma,double_fma,double_fma_coeff}.c
cases/quadratic_cases.h, cases/cases.json
environment.json, build_manifest.json
raw/kernel_<v>.csv, raw/route_<v>.csv
raw/kernel_metrics_<v>.csv, raw/route_metrics_<v>.csv
raw/curated_kernel.csv, raw/curated_route.csv
raw/microbench_<v>_r*.json, raw/routebench_<v>_r*.json
raw/fma_verify.json, raw/{linearity,curated}*
summary.json
logs/{build_commands,accuracy_*,microbench_*,routebench_*}.log
summary.json is the machine-readable aggregate; the script also prints the
coverage counts, per-variant ULP distributions, the curated case table, codegen
evidence and median ns/call.
Interpretation caveats
- FMA improves the rounding of one product only. It cannot restore the
information already lost in the double inputs and in the coefficient sums
(
d = x - c,q = w + v, and theqq/dq/ddaccumulations). The data should be read stage by stage. - A kernel UNCERTAIN is not a failure: the shared route fallback may confirm the
entry. A kernel MISS bypasses the fallback entirely, so growing/outward
false-MISS families are exercised through dedicated
rr<0route fixtures and reported both as the raw kernel decision (kern_status) and the route outcome. This benchmark does not claim that the fallback rescues a raw kernel MISS on the same case; it only observes that more fallback is used to confirm inaccurate candidates. - The double uncertainty band differs from the long-double one by the precision
term: production uses
64·(DBL_EPSILON + LDBL_EPSILON)·scalewhile the double variants use64·(DBL_EPSILON + DBL_EPSILON)·scale; sinceLDBL_EPSILON ≪ DBL_EPSILONthis is roughly a factor of two in the band width, which only matters exactly at the UNCERTAIN/MISS border. - Number/scale results are machine- and compiler-specific;
environment.jsonrecords the source hash, compiler, flags and platform. - This benchmark does not establish a universal guarantee, only the sampled behaviour on the frozen fixture set.