Skip to content

Add generalized Laguerre polynomials for real alpha - #1632

Merged
NAThompson merged 1 commit into
developfrom
generalized-laguerre
Nov 5, 2026
Merged

NAThompson merged 1 commit into
developfrom
generalized-laguerre

Conversation

@NAThompson

Copy link
Copy Markdown
Collaborator

laguerre(n, alpha, x) with a floating-point alpha evaluates the generalized Laguerre polynomial L_n^α(x) instead of truncating alpha to an integer; associated polynomials now also use the compensated recurrence.

Requested in #1128 (now on the #303 wishlist). Gauss–Laguerre quadrature and laguerre_zeros(n, alpha) for real α landed in #1517 and #1609; evaluating L_n^α itself was the missing piece. On develop, laguerre(3, 0.5, 1.2) silently converts 0.5 to the unsigned order 0 and returns L_3(1.2) = −0.728 instead of L_3^{1/2}(1.2) = −0.8305.

API. laguerre(n, alpha, x) and laguerre(n, alpha, x, pol) take any real α when its type is floating point (L_n^α is a polynomial in α, so no domain restriction). A non-negative integer order still selects the associated polynomial and leaves the result type to x alone, so laguerre(n, 2, 1.0f) is still float; a floating α promotes with x. A negative int order is now treated as the real α it is (on develop it wrapped to about 4·10⁹).

Source compatibility. Calls that passed a fractional floating-point order, like laguerre(n, 2.7, x), used to compute L_n^2 and now compute L_n^2.7, without a diagnostic. An integer-valued floating order gives the same value as before, but laguerre(n, 2.0, 1.5f) now returns double instead of float.

Method. The compensated three-term recurrence that laguerre_zeros already uses (laguerre_family::compensated_value, from #1609): the rounding error of each step, and of its coefficients 2c + 1 + α and c + α, is carried forward by the same recurrence, as plain laguerre(n, x) does. The associated polynomials with integer m used the plain recurrence and now go through it too.

Accuracy (against 600-bit sums Σ (−1)^k C(n+α, n−k) x^k/k! at the double arguments): correctly rounded in double on every plotted point; the 18 test references (n up to 500, α from −1.5 to 1000) are within 4 ε in float and double, and in cpp_bin_float_50 to the references' precision.

laguerre(50, 3, x), develop
laguerre(50, 3, x), this PR
laguerre(50, 0.5, x)
laguerre(30, -0.7, x)
laguerre(200, 12.25, x)

Performance (google/benchmark, Apple M1 Pro, -O2, reporting/performance/laguerre_performance.cpp, x = 3.5):

n 8 16 64 256 512
laguerre(n, x) (unchanged) 35 ns 91 ns 523 ns 2.32 µs 4.72 µs
laguerre(n, 3, x), develop 7 ns 21 ns 151 ns 975 ns 2.11 µs
laguerre(n, 3, x), this PR 56 ns 116 ns 553 ns 2.30 µs 4.64 µs
laguerre(n, 0.5, x) 56 ns 116 ns 551 ns 2.30 µs 4.70 µs

The associated polynomials now cost what the plain ones already did (2.2–8× more than before) in exchange for being correctly rounded instead of tens of ulps off.

🤖 Generated with Claude Code

laguerre(n, alpha, x) with real alpha no longer truncates alpha.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@NAThompson
NAThompson merged commit 0ee903d into develop Nov 5, 2026
51 checks passed
@NAThompson
NAThompson deleted the generalized-laguerre branch November 5, 2026 03:58
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