Skip to content

v2.3.1 — Correctness patch

Choose a tag to compare

@OldCrow OldCrow released this 26 Aug 03:44
· 54 commits to main since this release
v2.3.1
a981d4f

Correctness patch — no API change; upgrading from v2.3.0 is a drop-in swap. Eight issues closed (#102, #105, #106, #112, #115, #116, #117, #118) across five PRs (#120#124), each with fail-first regression gates. Correctness suite grows 53 → 58.

Fixed

  • SIMD: vector_log_{sse2,avx,avx2,avx512} gained the missing unordered-compare NaN blend — a NaN lane previously exited as 710.188, so LogNormal batch cdf(NaN) returned 1 and pdf(NaN) returned 0 through the public API (#105).
  • Batch NaN propagation: 16 of 19 distributions returned finite, plausible values for NaN batch inputs (uniform batch pdf(NaN) gave the full in-support density; Discrete batch cdf(NaN) gave −214748364.7). NaN is now classified ahead of every range check and propagates, mirroring each scalar contract; all 19 distributions are gated (#102).
  • Von Mises: the κ > 1000 wrapped-normal CDF fallback wrapped x alone instead of x − μ, returning F = 0 where the truth is 1 for every x on the far side of the ±π seam; new κ = 2000/10000 accuracy-gate buckets (#106).
  • NegativeBinomial/Geometric: getQuantile's search bound was cast to int unguarded; past INT_MAX the search collapsed and every quantile returned 0 (Geometric(1e-9).getQuantile(0.5) = 0, truth ≈ 6.93e8). Bound clamped to 2⁵³ before narrowing to int64; the search evaluates the incomplete beta directly (#116).
  • Stream I/O: operator>> round-trip was broken for Discrete, Uniform and Beta (whitespace tokenisation vs their own comma-space output); rewritten on Gaussian's getline pattern, output formats unchanged (#115).
  • CPUID gates: the AVX-512 tier is now gated on AVX-512DQ (the kernels use five DQ intrinsics — F alone is an illegal-instruction fault on redistributed binaries) and on XCR0[7:5] opmask/ZMM state; the AVX2 tier is gated on FMA; the MSVC configure probe executes a DQ instruction; SIMDPolicy uses the same gates so the two reporting ladders agree (#117).
  • ParallelUtils::parallelFor silently discarded exceptions thrown inside chunks, returning partial output as success. It now waits for all chunks, then rethrows the first exception (#118). WorkStealingPool::parallelFor still swallows by design; the asymmetry is documented.

Changed

  • Batch span overloads: the no-aliasing contract (input and output spans must not overlap) is documented at every surface and enforced by a debug-mode assert at the central dispatch point (#112). Zero cost in Release.
  • tools/accuracy_sweep.cpp emits NaN/±inf special rows for the discrete family too; grid grows 5928 → 6063 rows. The regenerated AVX-512 characterization block shows 0 batch-NaN violations and 63 total (all remaining rows belong to the v2.3.2 ±inf-contract and large-parameter classes).
  • libstats.pc is relocatable (prefix derives from ${pcfiledir}).

Validation

58/58 correctness native on Zen 4 AVX-512 (MSVC Release, 2026-08-25); CI green on all merges. Kaby Lake (AVX2+FMA) and M1 (NEON) native validation runs are pending and tracked for the v2.3.1 matrix. Full details in CHANGELOG.md and docs/ACCURACY_CHARACTERIZATION.md.

🤖 Generated with Claude Code