Skip to content

Promote the Bessel order against the argument - #552

Open
andreasnoack wants to merge 1 commit into
masterfrom
fix/bessel-same-precision
Open

Promote the Bessel order against the argument#552
andreasnoack wants to merge 1 commit into
masterfrom
fix/bessel-same-precision

Conversation

@andreasnoack

@andreasnoack andreasnoack commented Aug 21, 2026

Copy link
Copy Markdown
Member

Continues the type-stability work from #549 by fixing the largest group of broken
entries in the sweep, 43 of them, and closes #547 on the way. The sweep goes from
280 pass / 58 broken to 325 pass / 15 broken; of the 15 that remain, 12 are the
incomplete gamma and expint entries that #550 addresses.

The Bessel order forced Float64

besselj(nu::Real, x::AbstractFloat) and its seven siblings ended in

real(besselj(float(nu), complex(x)))

float(nu) maps every Integer and Rational order to Float64, and the complex
method then promoted the argument up to match, so the argument's precision was lost:

julia> besseli(2, Float16(1))          # before
0.1357476  # ::Float64

The fix is to promote the two arguments against each other in the value domain
(promotereal) rather than putting nu through float first, so that the order
adopts the precision of the argument. The same change to the besselh/besselhx
layer covers hankelh1/hankelh2 and the scaled variants, and
sphericalbessel[jy] get a promoting method plus a same-precision one so that the
half-integer order nu + one(nu)/2 no longer widens an integer nu.

besselj0/besselj1/bessely0/bessely1 on ComplexF32, and jinc on
ComplexF32, are fixed by the same change: they are defined as besselj(0, z) etc.,
so an integer order was the whole problem there too.

Fixes #547

That fall-through also had no method to land on for a Float16 argument of integer
order, so besselj(2, Float16(1)) recursed until the stack overflowed. Adding the
two missing Cint methods at Float16 fixes it, and the sweep's integer-order
testset can now include Float16.

Two details worth a look

  • besselh's method for real arguments went from Float64 to the hardware floats,
    so that a Float16/Float32 argument keeps its precision there as well. It is
    deliberately not extended to BigFloat: besselj/bessely support BigFloat
    for integer orders only, so a BigFloat method there would work for
    besselh(1, big(1.0)) and throw a MethodError for besselh(1.2, big(1.0)). The
    Complex{Float16} and Complex{Float32} narrowing methods for besselh became
    redundant and are gone.
  • sphericalbesselj's small-argument threshold reads sqrt(eps(zero(T))), which is
    sqrt(nextfloat(0.0)), about 2e-162 — so that branch effectively only triggers
    at x == 0. It looks like eps(T) was meant, but changing it changes results, so
    I kept the existing behaviour and left it out of this PR.

Accuracy: every newly narrow result is within half an ulp of the correctly rounded
Float64 reference.

Prior art

#234 aimed at the same goal in 2020 and independently arrived at the same two
besselj/bessely Cint/Float16 methods. It fixed the precision by converting
the result (convert(typeof(x), ...)), which hides the mixed-precision arithmetic
rather than preventing it; this PR promotes the arguments instead. #234 can be closed
once this lands.

The text of this PR and the commit was written by Claude.

@giordano

Copy link
Copy Markdown
Member

Stacked on #550

Claude loves to talk about stacking PRs, but not actually stacking them

@andreasnoack
andreasnoack force-pushed the fix/bessel-same-precision branch from ec5dcdd to 8d9cc23 Compare August 21, 2026 11:14
@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.71%. Comparing base (b2a7190) to head (e83eba7).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #552      +/-   ##
==========================================
+ Coverage   94.67%   94.71%   +0.03%     
==========================================
  Files          14       14              
  Lines        3023     3025       +2     
==========================================
+ Hits         2862     2865       +3     
+ Misses        161      160       -1     
Flag Coverage Δ
unittests 94.71% <100.00%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

`besselj(nu::Real, x::AbstractFloat)` and its siblings promoted the order
with `float(nu)`, which maps every `Integer` and `Rational` order to
`Float64` and then dragged the argument up with it, so `besseli(2,
Float16(1))` returned a `Float64`. Promote the two arguments against each
other instead, in the value domain, so that the order adopts the precision
of the argument.

The same fall-through had no method to land on for a `Float16` argument of
integer order, and recursed until the stack overflowed. Add the missing
`besselj`/`bessely` methods for `Cint` orders at `Float16`, which fixes
that too.

`besselh`'s method for real arguments is generalised from `Float64` to the
hardware floats so that a narrow argument keeps its precision there as
well; it is deliberately not extended to `BigFloat`, since `besselj` and
`bessely` support `BigFloat` for integer orders only.

`sphericalbessel[jy]` gain a promoting method and a same-precision one, so
that the half-integer order `nu + one(nu)/2` no longer widens an integer
`nu` to `Float64`.

Fixes #547.
@andreasnoack
andreasnoack force-pushed the fix/bessel-same-precision branch from 8d9cc23 to e83eba7 Compare August 21, 2026 11:29
@andreasnoack andreasnoack changed the title Promote the Bessel and incomplete gamma order against the argument Promote the Bessel order against the argument Aug 21, 2026
@andreasnoack
andreasnoack changed the base branch from fix/expint-same-precision to master August 21, 2026 11:29
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.

besselj/bessely stack overflow for an integer order and a Float16 argument

2 participants