Deterministic ephemeris: vendor musl transcendentals, pin FP contraction - #29
Merged
Merged
Conversation
Positions were not bit-reproducible across environments because the vendored astronomy.c called the host libm's transcendentals, whose last-ULP results differ between macOS point releases and vs glibc. Downstream calibration corpora baselined against these positions broke whenever the runner OS rolled forward. - Vendor a musl 1.2.5 double-precision math subset (sin, cos, tan, asin, acos, atan, atan2, exp, log10, pow, cbrt, hypot + internals) into Sources/CLibAstronomy/detmath/, all symbols ak_-prefixed so nothing can resolve to the host libm at link time. - Redirect astronomy.c onto it via ak_detmath.h (local patch #6: one include line) and pin FMA contraction off for the whole translation unit with #pragma STDC FP_CONTRACT OFF (source-level; unsafeFlags would make the package unconsumable as a dependency). pow.c also #undefs __FP_FAST_FMA to kill an arm64-vs-x86 path divergence. - Route the three Swift transcendental call sites (MoonPhase.cos, FixedStar.atan2/asin) through the new public ak_math.h. sqrt/fmod/ floor/ceil/fabs stay on the host (IEEE-exact everywhere). - Add ReproducibilityTests: 158 bit-exact golden assertions (Double.bitPattern) covering all bodies, topocentric coordinates, rise/set and moon-phase searches, FixedStar, and Chiron; identical in debug and release. - Add a CI nm guard on the Linux job failing on any undefined host transcendental reference in the built objects. - Document as local patch #6 in MAINTAINING.md with a deterministic- math section; musl MIT license in THIRD_PARTY_NOTICES; CHANGELOG flags the one-time last-ULP shift requiring downstream re-baseline. Closes #28 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Closes #28.
Problem
Ephemeris positions were not bit-reproducible across environments: the vendored
astronomy.ccalled the host libm's transcendentals (sin×137,cos×97,atan2×14, …), whose last-ULP results differ between macOS point releases (26.4 vs 26.5.2) and vs glibc. Positions drifted by sub-arcminute amounts per environment, silently flipping ~6 borderline cases in AstrologyKit's expert-locked calibration corpus and making hosted CI impossible to keep green.Fix
Vendor the math, pin the codegen, lock it with bit-exact tests.
Sources/CLibAstronomy/detmath/— musl 1.2.5 double-precision subset (sin cos tan asin acos atan atan2 exp log10 pow cbrt hypot+ kernels:__rem_pio2,__rem_pio2_large,scalbn, exp/pow tables, error helpers). Every symbol isak_-prefixed (including internals) so nothing can collide with or resolve to the host libm at link time. musl attribution preserved; MIT license added toTHIRD_PARTY_NOTICES.astronomy.c(one include line, documented in the vendoring note):ak_detmath.hredirects the 12 transcendentals toak_*and opens with#pragma STDC FP_CONTRACT OFF, pinning FMA contraction off for the whole translation unit. Build logs confirm Xcode defaults to-ffp-contract=on, so the pragma is load-bearing. Source-level on purpose —unsafeFlagswould make the package unconsumable as a dependency.pow.c#undefs__FP_FAST_FMA— musl's pow has an FMA path that is compiled on Apple Silicon but not x86; exactly the cross-arch divergence this PR eliminates.MoonPhase.illumination'scos,FixedStar'satan2/asin) now callak_*via the new publicinclude/ak_math.h.sqrt/fmod/floor/ceil/fabsdeliberately stay on the host — they are IEEE-exact/correctly rounded everywhere and carry no drift risk.ReproducibilityTests— 158 bit-exact golden assertions (Double(bitPattern:), exact==): ecliptic lon/lat/dist for 10 bodies at 4 instants (1980/2000/2026/2050), equatorial + topocentric coordinates, sunrise/sunset and full-moon search times,FixedStarandMoon.illuminationSwift paths, Chiron. Identical bit patterns in debug and release. These running green on both the macOS and Ubuntu CI jobs is the cross-environment proof from the issue's acceptance criteria.nmguard on the Linux job: fails if any built object regains an undefined reference to a host transcendental (so a future call site can't silently escape the redirect).Accuracy
Unchanged at the meaningful scale: all JPL Horizons validation suites (±1–1.5′) and audit validation suites pass untouched. The change is last-ULP only.
Vendored math shifts last-ULP values relative to every current host libm, so AstrologyKit must re-baseline its calibration corpus once against this version. After that, the baseline holds permanently on every OS, runner image, and toolchain — which is the point.
Verification
swift test(debug): 579/579 in 175 suites ✅swift test -c release: 579/579, same golden bit patterns ✅swift test --sanitize=thread: 579/579 ✅swift-format lint --strict(CI config): clean ✅nmaudit: zero undefined host-transcendental refs inastronomy.oand detmath objects; nofma✅🤖 Generated with Claude Code