8000 Numerically stable Sinh, Cosh, Asinh and Acosh by arigon · Pull Request #474 · gomlx/gomlx · GitHub
[go: up one dir, main page]

Skip to content

Numerically stable Sinh, Cosh, Asinh and Acosh - #474

Merged
janpfeifer merged 1 commit into
gomlx:mainfrom
arigon:stable-hyperbolic
Oct 24, 2026
Merged

janpfeifer merged 1 commit into
gomlx:mainfrom
arigon:stable-hyperbolic

Conversation

@arigon
@arigon arigon commented Oct 23, 2026
Copy link
Copy Markdown
Contributor

Follow-up to #473, as discussed in gomlx/onnx-gomlx#94: makes the hyperbolic functions numerically stable at the edges.

  • Sinh: computed on |x| as (t + t/(t+1))/2 with t = Expm1(|x|), so there is no cancellation of e^x - e^-x for |x| close to 0 (before: Sinh(1e-10) = 0). For |x| > 20 it uses exp(|x| - ln 2), which only overflows where sinh(x) itself does (before: Sinh(89) was +Inf in Float32, although sinh(89) ≈ 2.2e38).
  • Cosh: the same exp(|x| - ln 2) for |x| > 20.
  • Asinh: ln(|x|) + ln 2 above 1/sqrt(epsilon) (4096 for Float32, 2^26 for Float64), where x² loses precision or overflows (before: NaN for |x| ≳ 1e19 in Float32 / 1e154 in Float64 and for ±Inf).
  • Acosh: the same large-value branch (before: +Inf for x ≳ 1.7e38 in Float32), and Log1p((x-1) + sqrt(x-1)·sqrt(x+1)) for more precision close to 1.
  • Expm1: added its gradient (Expm1(x) + 1), which Sinh now needs.

Both branches are always computed with Where; each one only sees the values it is selected for (the others are clamped to the threshold), so the discarded branch never produces Inf/NaN, neither in the forward pass nor in the gradient. The Float32 promotion for half precision from #473 is unchanged.

Tests: TestHyperbolicTrigNumericalStability (all official backends) covers tiny values, values on both sides of the thresholds, overflow cases, ±Inf and NaN in Float32 and Float64, plus gradients in the large-value branches and of Expm1. The existing TestHyperbolicTrig and the rest of core/graph pass.

🤖 Generated with Claude Code

@janpfeifer
Copy link
Copy Markdown
Contributor

Thanks. I noticed it even add a test for the gradient, which is nice it works (it can be tricky with where).

@janpfeifer
janpfeifer merged commit 22ca478 into gomlx:main Oct 24, 2026
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 3BD3 request may close these issues.

2 participants

0