[M0-CORE-04] SimMath fpx16_16 backend (default) - #4
Merged
Merged
Conversation
Implements roadmap step M0-CORE-04 (ADR 0002, PRD §10.3, FR-3.3):
the Q16.16 fixed-point type and its wiring in as the DEFAULT SimMath
backend, with the same op surface as M0-CORE-03.
- include/laige/fpx16_16.h: laige::fpx16_16 — int32_t raw, value =
raw / 2^16, range [-32768, 32767.99998474], resolution 2^-16. All
arithmetic in int64_t, defined (no UB, CPP-004) for every input:
add/sub/mul/div/negate saturate to the range; rounding is
round-to-nearest ties-to-even (the fixed-point analogue of IEEE
round-to-nearest-even); divide by zero is defined (x/0 -> ±max with
the sign of x, 0/0 -> +0 — the saturation analogue of IEEE ±inf);
sqrt(negative) is defined as +0; fromInt32/fromFloat saturate, NaN
-> +0; toInt32/toFloat carry documented single-rounding semantics.
No NaN/Inf exist (total order); the type has no implicit scalar
constructors and no arithmetic operators — construction goes through
fromInt32/fromFloat, computation through the named static ops /
SimMath (PRD §10.3, CORE-008).
- sim_math.h: Fpx16_16 backend (delegates to the type ops) and the
SimMathFpx16 alias — the default backend per ADR 0002 (the
determinism.math config plumbing lands with the config step,
FR-1.5). Additive template changes only: isNaN/isInf become
backend-delegated (Fp32Pinned carries the IEEE implementation,
semantics unchanged) and normalize compares against Scalar{}
(identical for both backends).
- sim_math_fixed.cpp: explicit instantiation of SimMath<Fpx16_16>
(linkable symbol in both static and shared variants, NFR-8.9).
- tests/laige-core/math_fixed_tests.cpp: ctest -R math_fixed (24
tests, 7 suites) — exhaustive edge cases (min/max, wrap candidates),
rounding ties for mul/div/toInt32/fromFloat (and the proof that sqrt
of an integer has none), the full saturation/divide-by-zero policy,
conversion round trips (20k-raw LCG scan), the op surface, and the
length accuracy bound (accurate while the sum of squares stays in
the Q16.16 range, saturating beyond — documented). Determinism
property: a fixed 4096-tick op sequence run through the SimMath ops
and through an independent raw-int64 reference agrees bit-for-bit,
and its FNV-1a state hash equals the committed known-answer
constant 0xF02728762777C581.
- docs: sim_math.md gains the fpx16_16 policy section (rounding,
saturation, divide-by-zero, conversions, the length bound, the
determinism scope), quick start now leads with the default backend;
building.md and README list the new backend and the math_fixed
entry; roadmap step marked done.
Verify (local, 2026-09-10): ctest -R math_fixed green; full ctest
10/10 on five trees — g++ 16.2.1 static, g++ ASan+UBSan (canonical
LAIGE_ASAN=ON), g++ shared (LAIGE_BUILD_SHARED=ON), g++ TSan, and
clang++ 22.1.8 — with the known-answer determinism hash identical on
the two different compiler builds (the two-compiler property the step
names; CI hookup lands in M1-DET-04). Zero warnings under
-Wall -Werror -fno-exceptions -fno-rtti.
Windows CI (first MSVC build of the logging code — the ci:windows
label selects the Windows P0 job per PR) fails on the C runtime
deprecation:
logging.cpp(192): warning C4996: 'fopen': ... Consider using
fopen_s instead.
logging.cpp(192): error C2220: the following warning is treated as
an error
MSVC's CRT deprecates plain fopen/remove (C4996), and the engine
policy treats every /W4 warning as an error (/WX). The fix routes
the five file-open sites and eight file-removal sites through a small
file-local portable helper per translation unit (CPP-009 compile-time
platform boundary): MSVC takes the secure CRT variants fopen_s /
remove_s (out-parameter + errno_t, identical success semantics —
NULL/failed on error, which the existing error paths already handle);
every other supported compiler keeps the standard std::fopen /
std::remove unchanged.
Verified locally (no MSVC toolchain on this machine — the secure-CRT
branch is verified by the Windows CI job on this push):
- all five local trees green after the change: g++ static
(build, 10/10), g++ ASan+UBSan (build-asan, 10/10), clang++
(build-clang, 10/10, KAT hash unchanged), g++ shared
(build-shared, 10/10), g++ TSan (build-tsan, 10/10);
- the non-MSVC branches are semantically identical to the previous
code (same std::fopen/std::remove calls), so no behavior change.
No other Windows-CI failure class is expected: the full 8-job merge
matrix was green on the M0-CORE-01 tree (run 34525402022) with
result.h/errors.h in place, which rules out C4324/C4514 at /W4 for
this code, and result_status_tests.cpp (with non-CP1252 comment
characters) built green on that same Windows run, ruling out C4819
for this runner's code page.
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.
What
Implements roadmap step M0-CORE-04 (ADR 0002, PRD §10.3, FR-3.3): the
laige::fpx16_16Q16.16 fixed-point type and its wiring in as the default SimMath backend, with the same op surface as M0-CORE-03.include/laige/fpx16_16.h—int32_t raw, value = raw/2^16, range [-32768, 32767.99998474], resolution 2^-16. All arithmetic inint64_t, defined for every input (CPP-004, no UB): saturating add/sub/mul/div/negate; round-to-nearest ties-to-even (the fixed-point analogue of IEEE round-to-nearest-even); divide-by-zero defined (x/0 → ±maxwith the sign of x,0/0 → +0— the saturation analogue of IEEE ±inf);sqrt(negative) → +0; documentedfromInt32/toInt32/fromFloat/toFloatconversions (NaN → +0, saturation, single-rounding semantics). No NaN/Inf exist (total order); no implicit scalar constructors and no arithmetic operators — construction viafromInt32/fromFloat, computation via the named static ops / SimMath (PRD §10.3, CORE-008).sim_math.h—Fpx16_16backend (delegates to the type ops) +SimMathFpx16alias, marked as the default backend per ADR 0002 (thedeterminism.mathconfig plumbing lands with the config step, FR-1.5). Additive template changes only:isNaN/isInfbecome backend-delegated (Fp32Pinnedcarries the IEEE implementation — semantics unchanged) andnormalizecompares againstScalar{}(identical for both backends).sim_math_fixed.cpp— explicitSimMath<Fpx16_16>instantiation (linkable symbol in both static and shared variants).tests/laige-core/math_fixed_tests.cpp—ctest -R math_fixed, 24 tests / 7 suites: exhaustive edge cases (min/max, wrap candidates), rounding ties for mul/div/toInt32/fromFloat (plus the no-ties-for-sqrt fact), the full saturation/divide-by-zero policy, conversion round trips (20k-raw LCG scan), the op surface, and the documentedlengthaccuracy bound (accurate while the sum of squares stays in the Q16.16 range, saturating beyond). Determinism property: a fixed 4096-tick op sequence run through the SimMath ops and through an independent raw-int64 reference agrees bit-for-bit, and its FNV-1a state hash equals the committed known-answer constant0xF02728762777C581.docs/api/sim_math.mdgains the fpx16_16 policy section (rounding, saturation, divide-by-zero, conversions, the length bound, the ARCH-010 determinism scope); quick start now leads with the default backend;building.md/README.mdlist the new entry; roadmap step marked done.Verify (local, 2026-09-10)
ctest -R math_fixedgreen; fullctest10/10 on five trees: g++ 16.2.1 static, g++ ASan+UBSan (canonicalLAIGE_ASAN=ON), g++ shared (LAIGE_BUILD_SHARED=ON), g++ TSan, and clang++ 22.1.8.-Wall -Werror -fno-exceptions -fno-rtti(NFR-8.10).Notes
ctest -R math_floatstays green in every tree.lengthsaturates beyond |v| ≈ 181.02 per component (the sum of squares must stay in the Q16.16 range). Local sim math stays well inside; world-span distances belong to M1-DET-02.