Promote the Bessel order against the argument - #552
Open
andreasnoack wants to merge 1 commit into
Open
Conversation
Member
Claude loves to talk about stacking PRs, but not actually stacking them |
andreasnoack
force-pushed
the
fix/bessel-same-precision
branch
from
August 21, 2026 11:14
ec5dcdd to
8d9cc23
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
`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
force-pushed
the
fix/bessel-same-precision
branch
from
August 21, 2026 11:29
8d9cc23 to
e83eba7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Continues the type-stability work from #549 by fixing the largest group of
brokenentries 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
expintentries that #550 addresses.The Bessel order forced
Float64besselj(nu::Real, x::AbstractFloat)and its seven siblings ended infloat(nu)maps everyIntegerandRationalorder toFloat64, and the complexmethod then promoted the argument up to match, so the argument's precision was lost:
The fix is to promote the two arguments against each other in the value domain
(
promotereal) rather than puttingnuthroughfloatfirst, so that the orderadopts the precision of the argument. The same change to the
besselh/besselhxlayer covers
hankelh1/hankelh2and the scaled variants, andsphericalbessel[jy]get a promoting method plus a same-precision one so that thehalf-integer order
nu + one(nu)/2no longer widens an integernu.besselj0/besselj1/bessely0/bessely1onComplexF32, andjinconComplexF32, are fixed by the same change: they are defined asbesselj(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
Float16argument of integerorder, so
besselj(2, Float16(1))recursed until the stack overflowed. Adding thetwo missing
Cintmethods atFloat16fixes it, and the sweep's integer-ordertestset can now include
Float16.Two details worth a look
besselh's method for real arguments went fromFloat64to the hardware floats,so that a
Float16/Float32argument keeps its precision there as well. It isdeliberately not extended to
BigFloat:besselj/besselysupportBigFloatfor integer orders only, so a
BigFloatmethod there would work forbesselh(1, big(1.0))and throw aMethodErrorforbesselh(1.2, big(1.0)). TheComplex{Float16}andComplex{Float32}narrowing methods forbesselhbecameredundant and are gone.
sphericalbesselj's small-argument threshold readssqrt(eps(zero(T))), which issqrt(nextfloat(0.0)), about2e-162— so that branch effectively only triggersat
x == 0. It looks likeeps(T)was meant, but changing it changes results, soI 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
Float64reference.Prior art
#234 aimed at the same goal in 2020 and independently arrived at the same two
besselj/besselyCint/Float16methods. It fixed the precision by convertingthe result (
convert(typeof(x), ...)), which hides the mixed-precision arithmeticrather 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.