Skip to content

fix: Kahan summation for numerical stability, plus formatting pass#57

Merged
erfanjazebnikoo merged 2 commits into
devfrom
fix/kahan-summation-numerical-stability
Jul 10, 2026
Merged

fix: Kahan summation for numerical stability, plus formatting pass#57
erfanjazebnikoo merged 2 commits into
devfrom
fix/kahan-summation-numerical-stability

Conversation

@erfanjazebnikoo

Copy link
Copy Markdown
Member

Summary

Direct response to r/C_Programming (Axman6 flagged numx_stats_mean, EpochVanquisher flagged numx_integrate_simpson), both verified true against the real code before fixing.

Applies Kahan (compensated) summation to every summation loop where n can reach a size that matters: numx_stats_mean, numx_vec_dot, numx_vec_norm (L1/L2), numx_integrate_trap, numx_integrate_simpson, and signal.c's convolve/correlate/fir. Left numx_integrate_gauss (<=8 terms) and the matrix functions (<=32, bounded by NUMX_MAX_MAT_ROWS) alone, negligible benefit there for the added complexity. numx_stats_variance already used Welford's algorithm, no change needed.

Verification

  • Two new regression tests using a genuinely adversarial input (2^24 followed by 255x 1.0f, where naive summation loses every trailing term, confirmed via independent Python check before writing the fix)
  • 337/337 tests passing (up from 335)
  • Strict -std=c99 -pedantic-errors -Wall -Wextra -Werror on gcc and clang, float32 and float64, across the whole project
  • Clean under AddressSanitizer and UndefinedBehaviorSanitizer

Also included

A project-wide clang-format pass (whitespace/layout only) across src/, include/, examples/, and validation/c/. Verified value-preserving two ways: diffed extracted numeric literals for the NTT twiddle tables (identical), and a whitespace/backslash-normalized token diff for examples/esp32_ntt_test/main/main.c (which can't be compiled locally, no ESP-IDF toolchain here), also identical.

Direct response to r/C_Programming feedback (Axman6 on numx_stats_mean,
EpochVanquisher on numx_integrate_simpson), both verified true against
the actual code before fixing, not just taken at face value.

Applies Kahan (compensated) summation to every summation loop where n
can reach a size where accumulated float32 rounding error is a real
concern: numx_stats_mean, numx_vec_dot, numx_vec_norm (L1/L2),
numx_integrate_trap, numx_integrate_simpson, and signal.c's convolve,
correlate, and fir. numx_stats_variance already used Welford's algorithm
and needed no change. Left numx_integrate_gauss (bounded to <=8 terms)
and the matrix functions (bounded to <=32 by NUMX_MAX_MAT_ROWS) alone,
naive summation error at those sizes is genuinely negligible and Kahan
would be complexity without real benefit.

Added regression tests (test_stats_mean_kahan_stress,
test_vec_dot_kahan_stress) using a genuinely adversarial input: a leading
value of 2^24 followed by 255 values of 1.0f. At that magnitude float32's
ULP is already 2.0, so naive summation loses every single trailing
increment (255 confirmed lost in an independent Python check before
writing the fix), while Kahan summation lands within 1 ULP of the true
answer. Both new tests pass; 337/337 total, up from 335.

Verified: strict -std=c99 -pedantic-errors -Wall -Wextra -Werror on gcc
and clang, float32 and float64, across the whole project, not just the
touched files. Full suite clean under AddressSanitizer and
UndefinedBehaviorSanitizer.

Also includes a project-wide clang-format pass across src/, include/,
examples/, and validation/c/ (whitespace and layout only). Verified the
NTT twiddle-table reformatting is value-preserving by extracting and
diffing the numeric literals directly before and after: identical.
Missed in the previous commit's formatting pass. Verified value-preserving
the same way: stripped whitespace and macro line-continuation backslashes
from both versions and diffed, identical once normalized. This file can't
be compiled locally (ESP-IDF headers), so this token-level check stands in
for the strict-compile verification done on the files in src/.
@erfanjazebnikoo erfanjazebnikoo self-assigned this Jul 10, 2026
@erfanjazebnikoo
erfanjazebnikoo merged commit c8ef888 into dev Jul 10, 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