Skip to content

[M0-CORE-04] SimMath fpx16_16 backend (default) - #4

Merged
offdev merged 2 commits into
masterfrom
m0-core-04-simmath-fpx16
Sep 11, 2026
Merged

offdev merged 2 commits into
masterfrom
m0-core-04-simmath-fpx16

Conversation

@offdev

@offdev offdev commented Sep 11, 2026

Copy link
Copy Markdown
Owner

What

Implements roadmap step M0-CORE-04 (ADR 0002, PRD §10.3, FR-3.3): the laige::fpx16_16 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 — int32_t raw, value = raw/2^16, range [-32768, 32767.99998474], resolution 2^-16. All arithmetic in int64_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 → ±max with the sign of x, 0/0 → +0 — the saturation analogue of IEEE ±inf); sqrt(negative) → +0; documented fromInt32/toInt32/fromFloat/toFloat conversions (NaN → +0, saturation, single-rounding semantics). No NaN/Inf exist (total order); no implicit scalar constructors and no arithmetic operators — construction via fromInt32/fromFloat, computation via the named static ops / SimMath (PRD §10.3, CORE-008).
  • sim_math.h — Fpx16_16 backend (delegates to the type ops) + SimMathFpx16 alias, marked as 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 SimMath<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 documented length accuracy 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 constant 0xF02728762777C581.
  • Docs: docs/api/sim_math.md gains 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.md list the new 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.
  • The two-compiler property the step names: the known-answer determinism hash is identical on the two different compiler builds (g++ vs clang++). CI hookup for this property lands in M1-DET-04.
  • Zero warnings under -Wall -Werror -fno-exceptions -fno-rtti (NFR-8.10).

Notes

  • One additive change to the M0-CORE-03 template (backend-delegated classification) — fp32 behavior is bit-identical; ctest -R math_float stays green in every tree.
  • Documented bound: length saturates 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.

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.
@offdev
offdev merged commit 5c76991 into master Sep 11, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant