@@ -444,9 +444,9 @@ function _besseli(nu::Integer, x::T) where T <: Union{Float32, Float64}
444
444
sg = iseven (abs_nu) ? 1 : - 1
445
445
446
446
if x >= 0
447
- return besseli_positive_args (abs_nu, abs_x)
447
+ return besseli_positive_args (T ( abs_nu) , abs_x)
448
448
else
449
- return sg * besseli_positive_args (abs_nu, abs_x)
449
+ return sg * besseli_positive_args (T ( abs_nu) , abs_x)
450
450
end
451
451
end
452
452
@@ -507,17 +507,16 @@ besseli_underflow_check(nu, x::T) where T = nu > 140 + T(1.45)*x + 53*Base.Math.
507
507
Modified Bessel function of the first kind of order nu, ``I_{nu}(x)`` for positive arguments.
508
508
"""
509
509
function besseli_positive_args (nu, x:: T ) where T <: Union{Float32, Float64}
510
- iszero (nu) && return besseli0 (x)
511
- isone (nu) && return besseli1 (x)
512
-
513
- # use large argument expansion if x >> nu
514
- besseli_large_argument_cutoff (nu, x) && return besseli_large_argument (nu, x)
515
-
516
- # use uniform debye expansion if x or nu is large
517
- besselik_debye_cutoff (nu, x) && return besseli_large_orders (nu, x)
518
-
519
- # for rest of values use the power series
520
- return besseli_power_series (nu, x)
510
+ if besseli_large_argument_cutoff (nu, x)
511
+ # large argument expansion if x >> nu
512
+ return besseli_large_args (nu, x)
513
+ elseif besselik_debye_cutoff (nu, x)
514
+ # uniform debye expansion if x or nu is large
515
+ return besseli_large_orders (nu, x)
516
+ else
517
+ # power series
518
+ return besseli_power_series (nu, x)
519
+ end
521
520
end
522
521
523
522
"""
@@ -536,7 +535,7 @@ function _besselix(nu, x::T) where T <: Union{Float32, Float64}
536
535
isinf (x) && return T (Inf )
537
536
538
537
# use large argument expansion if x >> nu
539
- besseli_large_argument_cutoff (nu, x) && return besseli_large_argument_scaled (nu, x)
538
+ besseli_large_argument_cutoff (nu, x) && return besselix_large_args (nu, x)
540
539
541
540
# use uniform debye expansion if x or nu is large
542
541
besselik_debye_cutoff (nu, x) && return besseli_large_orders_scaled (nu, x)
@@ -589,65 +588,46 @@ end
589
588
590
589
# Implements the uniform asymptotic expansion https://dlmf.nist.gov/10.40.E1
591
590
# In general this is valid when x > nu^2
592
- """
593
- besseli_large_orders(nu, x::T)
594
591
595
- Debey's uniform asymptotic expansion for large order valid when v-> ∞ or x -> ∞
596
- """
597
- function besseli_large_argument (v, x:: T ) where T
598
- a = exp (x / 2 )
599
- coef = a / sqrt (2 * (π * x))
600
- return T (_besseli_large_argument (v, x) * coef * a)
592
+ function besseli_large_args (v, x:: T ) where T
593
+ e = exp (x / 2 )
594
+ return (e * besselix_large_args (v, x)) * e
601
595
end
602
596
603
- besseli_large_argument_scaled (v, x:: T ) where T = T (_besseli_large_argument (v, x) / sqrt (2 * (π * x)))
604
-
605
- function _besseli_large_argument (v, x:: T ) where T
606
- MaxIter = 5000
607
- S = promote_type (T, Float64)
608
- v, x = S (v), S (x)
609
-
610
- fv2 = 4 * v^ 2
611
- term = one (S)
612
- res = term
613
- s = - term
597
+ function besselix_large_args (v, x:: ComplexOrReal{T} ) where T
598
+ MaxIter = 1000
599
+ t = one (x)
600
+ invx = inv (8 * x)
601
+ s = t
614
602
for i in 1 : MaxIter
615
- offset = muladd (2 , i, - 1 )
616
- term *= muladd (offset, - offset, fv2) / (8 * x * i)
617
- res = muladd (term, s, res)
618
- s = - s
619
- abs (term) <= eps (T) && break
603
+ t *= - invx * ((4 * v^ 2 - (2 i - 1 )^ 2 ) / i)
604
+ s += t
605
+ abs (t) <= eps (T) && break
620
606
end
621
- return res
607
+ return s / sqrt ( 2 * (π * x))
622
608
end
623
609
624
- besseli_large_argument_cutoff (nu, x:: Float64 ) = x > 23.0 && x > nu^ 2 / 1.8 + 23 .0
625
- besseli_large_argument_cutoff (nu, x:: Float32 ) = x > 18.0f0 && x > nu^ 2 / 19.5f0 + 18 .0f0
610
+ besseli_large_argument_cutoff (nu, x:: Float64 ) = x > nu^ 2 / 2 + 19 .0
611
+ besseli_large_argument_cutoff (nu, x:: Float32 ) = x > nu^ 2 / 2 + 9 .0f0
626
612
627
613
# ####
628
614
# #### Power series for I_{nu}(x)
629
615
# ####
630
616
631
617
# Use power series form of I_v(x) which is generally accurate across all values though slower for larger x
632
618
# https://dlmf.nist.gov/10.25.E2
633
- """
634
- besseli_power_series(nu, x::T) where T <: Float64
635
619
636
- Computes ``I_{nu}(x)`` using the power series for any value of nu.
637
- """
638
620
function besseli_power_series (v, x:: ComplexOrReal{T} ) where T
639
621
MaxIter = 3000
640
- S = eltype (x)
641
- out = zero (S)
642
- xs = (x/ 2 )^ v
643
- a = xs / gamma (v + one (T))
644
- t2 = (x/ 2 )^ 2
622
+ s = zero (x)
623
+ t = one (x)
624
+ xx = x * x * T (0.25 )
645
625
for i in 0 : MaxIter
646
- out += a
647
- abs (a ) < eps (T) * abs (out ) && break
648
- a *= inv ((v + i + one (T)) * (i + one (T))) * t2
626
+ s += t
627
+ abs (t ) < eps (T) * abs (s ) && break
628
+ t *= xx / ((v + i + 1 ) * (i + 1 ))
649
629
end
650
- return out
630
+ return s * ((x / 2 ) ^ v / gamma (v + 1 ))
651
631
end
652
632
653
633
#=
0 commit comments