Skip to content

RFC: adopt explicit FMA as the numerical contract (feedback wanted)#96

Open
mario4tier wants to merge 1 commit into
devfrom
rfc/fma-numerical-contract
Open

RFC: adopt explicit FMA as the numerical contract (feedback wanted)#96
mario4tier wants to merge 1 commit into
devfrom
rfc/fma-numerical-contract

Conversation

@mario4tier

Copy link
Copy Markdown
Member

The tradeoff, up front: switching TA-Lib's value-path arithmetic to explicit fused multiply-add costs a one-time change in real-valued outputs bounded by a tested variation margin — every element stays numerically equal to today within |new − old| ≤ 1e-12 × max(1, |old|), and all integer/pattern outputs stay bit-identical (decision paths are never fused — candlestick penetration tests and SAR reversals are structurally excluded). In exchange: ~25% faster recursive indicators (measured: 427µs → 311µs per 200k-bar DEMA-class recursion) on every x86 CPU since 2013 and all ARM64, and — for the first time — bit-identical TA-Lib results across x86-64, ARM64, and every platform, because fma is one IEEE-754 correctly-rounded operation. The margin applies once at the transition; afterwards our regression gates return to bitwise comparison against the new frozen reference.

Full proposal: docs/fma-proposal.md in this PR — hardware/ecosystem trend, exact fusion policy (value-path only), the mechanical validation plan over the existing ≈118k-comparison differential fuzz matrix, artifact strategy (x86-64-v3 primary + baseline fallback), and timing (after the current lockstep optimization pass completes under the existing bit-exact contract).

Feedback wanted on four questions (see the end of the doc): (1) is the 1e-12 margin acceptable for your stored expected values / golden files? (2) x86-64-v3-primary artifacts: too early? (3) should a TA_NO_FMA build opt-out exist, and for how long? (4) does anything in your pipeline need pre-FMA bit-compatibility indefinitely?

This is a discussion PR — no implementation; it adds only the proposal document.

🤖 Generated with Claude Code

One-time output shift bounded by 1e-12*max(1,|old|) (integer outputs
bit-identical) in exchange for ~25% faster recursive indicators on all
post-2013 x86 / all ARM64, and bit-identical results across platforms
afterwards. Decision paths (candlestick penetration tests, SAR reversal)
are never fused. For community feedback; no implementation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mario4tier

Copy link
Copy Markdown
Member Author

I will leave that here in case someone care, but my mind is already set to modernize the code unless someone "insist" that TA-Lib should remain 100% bitwise-matching like the last 25 years...

To be clear, we are talking here of very small output differences (likely insignificant to most), in exchange with faster/modern code.

BTW, this debate is not specific to TA-Lib, there are similar recuring discussion in the Rust community about what "default" means and if it should adapt to more modern processor.

Forever matching floating point output is... complicated.

@mrjbq7

mrjbq7 commented Jul 5, 2026

Copy link
Copy Markdown
Member

I'm in favor! Let's move into the future!

@mario4tier

Copy link
Copy Markdown
Member Author

@mrjbq7 Great timing! I was coming back here to see how I should bubble this up to the largest python community.

Thanks for concurring.

Will probably move to FMA in late 2027. I want to do first a bunch of fixes and algo-level optimization while we still can do bit-perfect comparison against the 0.6.4 reference.

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.

2 participants