|
2 | 2 | [](https://github.com/heltonmc/Bessels.jl/actions/workflows/CI.yml?query=branch%3Amaster)
|
3 | 3 | [](https://codecov.io/gh/heltonmc/Bessels.jl)
|
4 | 4 |
|
| 5 | +A Julia implementation of Bessel's functions and modified Bessel's functions of the first and second kind. |
5 | 6 |
|
6 |
| -Implementations of Bessel's functions `besselj0`, `besselj1`, `bessely0`, `bessely1`, `besseli0`, `besseli1`, `besselk0`, `besselk1` in Julia. |
7 |
| -Most implementations are ported to Julia from the [Cephes](https://www.netlib.org/cephes/) math library originally written by Stephen L. Moshier in the C programming language |
8 |
| -which are (partly) used in [SciPy](https://docs.scipy.org/doc/scipy/reference/special.html#faster-versions-of-common-bessel-functions) and [GCC libquadmath](https://gcc.gnu.org/onlinedocs/libquadmath/). |
| 7 | +The library currently supports Bessel's function of the first and second kind for orders 0 and 1 and for any integer order for modified Bessel's functions for real arguments. |
9 | 8 |
|
10 | 9 | # Quick start
|
11 | 10 |
|
12 |
| -Only implemented for real arguments so far. |
13 |
| - |
14 | 11 | ```julia
|
15 |
| -using Bessels |
| 12 | +# add the package |
| 13 | +pkg> add https://github.com/heltonmc/Bessels.jl.git |
| 14 | + |
| 15 | +julia> using Bessels |
16 | 16 |
|
17 | 17 | # Bessel function of the first kind of order 0
|
18 | 18 | julia> besselj0(1.0)
|
19 | 19 | 0.7651976865579665
|
| 20 | + |
20 | 21 | julia> besselj0(1.0f0)
|
21 | 22 | 0.7651977f0
|
22 |
| - |
23 |
| -# Bessel function of the first kind of order 1 |
24 |
| -julia> besselj1(1.0) |
25 |
| -0.44005058574493355 |
26 |
| -julia> besselj1(1.0f0) |
27 |
| -0.4400506f0 |
28 |
| - |
29 |
| -# Bessel function of the second kind of order 0 |
30 |
| -julia> bessely0(1.0) |
31 |
| -0.08825696421567697 |
32 |
| -julia> bessely0(1.0f0) |
33 |
| -0.08825697f0 |
34 |
| - |
35 |
| -# Bessel function of the second kind of order 1 |
36 |
| -julia> bessely1(1.0) |
37 |
| --0.7812128213002888 |
38 |
| -julia> bessely1(1.0f0) |
39 |
| --0.7812128f0 |
40 |
| - |
41 |
| -# Modified Bessel function of the first kind of order 0 |
42 |
| -julia> besseli0(1.0) |
43 |
| -1.2660658777520082 |
44 |
| -julia> besseli0(1.0f0) |
45 |
| -1.266066f0 |
46 |
| - |
47 |
| -# Scaled modified Bessel function of the first kind of order 0 |
48 |
| -julia> besseli0x(1.0) |
49 |
| -0.46575960759364043 |
50 |
| -julia> besseli0x(1.0f0) |
51 |
| -0.46575963f0 |
52 |
| - |
53 |
| -# Scaled modified Bessel function of the first kind of order 1 |
54 |
| -julia> besseli1x(1.0) |
55 |
| -0.2079104153497085 |
56 |
| -julia> besseli1x(1.0f0) |
57 |
| -0.20791042f0 |
58 |
| - |
59 |
| -# Modified Bessel function of the second kind of order 0 |
60 |
| -julia> besselk0(1.0) |
61 |
| -0.42102443824070823 |
62 |
| -julia> besselk0(1.0f0) |
63 |
| -0.42102447f0 |
64 |
| - |
65 |
| -# Scaled modified Bessel function of the second kind of order 0 |
66 |
| -julia> besselk0x(1.0) |
67 |
| -1.1444630798068947 |
68 |
| -julia> besselk0x(1.0f0) |
69 |
| -1.1444632f0 |
70 |
| - |
71 |
| -# Modified Bessel function of the second kind of order 1 |
72 |
| -julia> besselk1(1.0) |
73 |
| -0.6019072301972346 |
74 |
| -julia> besselk1(1.0f0) |
75 |
| -0.6019073f0 |
76 |
| - |
77 |
| -# Scaled modified Bessel function of the second kind of order 1 |
78 |
| -julia> besselk1x(1.0) |
79 |
| -1.636153486263258 |
80 |
| -julia> besselk1x(1.0f0) |
81 |
| -1.6361537f0 |
82 | 23 | ```
|
83 | 24 |
|
| 25 | +# Supported functions |
| 26 | + |
| 27 | +- `besselj0(x)` |
| 28 | +- `besselj1(x)` |
| 29 | +- `bessely0(x)` |
| 30 | +- `bessely1(x)` |
| 31 | +- `besseli0(x)` |
| 32 | +- `besseli1(x)` |
| 33 | +- `besselk0(x)` |
| 34 | +- `besselk1(x)` |
| 35 | +- `besseli(nu, x)` |
| 36 | +- `besselk(nu, x)` |
| 37 | + |
| 38 | +Exponentially scaled versions of Modified Bessel's function can also be called with `besselix(nu, x)` and `besselkx(nu, x)`. |
| 39 | + |
84 | 40 | # Benchmarks
|
85 | 41 |
|
86 |
| -```julia |
87 |
| -# Bessels.jl |
88 |
| -julia> @benchmark besselj0(x) setup=(x=100.0*rand()) |
89 |
| -BenchmarkTools.Trial: 10000 samples with 999 evaluations. |
90 |
| - Range (min … max): 7.465 ns … 28.946 ns ┊ GC (min … max): 0.00% … 0.00% |
91 |
| - Time (median): 25.860 ns ┊ GC (median): 0.00% |
92 |
| - Time (mean ± σ): 24.915 ns ± 4.090 ns ┊ GC (mean ± σ): 0.00% ± 0.00% |
93 |
| - Memory estimate: 0 bytes, allocs estimate: 0. |
94 |
| - |
95 |
| - # SpecialFunctions.jl |
96 |
| - julia> @benchmark besselj0(x) setup=(x=100.0*rand()) |
97 |
| -BenchmarkTools.Trial: 10000 samples with 999 evaluations. |
98 |
| - Range (min … max): 9.050 ns … 79.412 ns ┊ GC (min … max): 0.00% … 0.00% |
99 |
| - Time (median): 51.677 ns ┊ GC (median): 0.00% |
100 |
| - Time (mean ± σ): 51.029 ns ± 5.653 ns ┊ GC (mean ± σ): 0.00% ± 0.00% |
101 |
| - Memory estimate: 0 bytes, allocs estimate: 0. |
102 |
| - ``` |
103 |
| - |
104 |
| - ```julia |
105 |
| - # Bessels.jl |
106 |
| - julia> @benchmark besselk1(x) setup=(x=100.0*rand()) |
107 |
| -BenchmarkTools.Trial: 10000 samples with 988 evaluations. |
108 |
| - Range (min … max): 47.781 ns … 97.672 ns ┊ GC (min … max): 0.00% … 0.00% |
109 |
| - Time (median): 47.950 ns ┊ GC (median): 0.00% |
110 |
| - Time (mean ± σ): 48.495 ns ± 2.656 ns ┊ GC (mean ± σ): 0.00% ± 0.00% |
111 |
| - Memory estimate: 0 bytes, allocs estimate: 0. |
112 |
| - |
113 |
| - # SpecialFunctions.jl |
114 |
| - julia> @benchmark besselk(1, x) setup=(x=10.0*rand()) |
115 |
| -BenchmarkTools.Trial: 10000 samples with 681 evaluations. |
116 |
| - Range (min … max): 184.962 ns … 2.122 μs ┊ GC (min … max): 0.00% … 81.41% |
117 |
| - Time (median): 377.081 ns ┊ GC (median): 0.00% |
118 |
| - Time (mean ± σ): 388.243 ns ± 96.971 ns ┊ GC (mean ± σ): 0.04% ± 0.81% |
119 |
| - Memory estimate: 16 bytes, allocs estimate: 1. |
120 |
| - ``` |
121 |
| - |
122 |
| -Comparing the relative speed (`SpecialFunctions.jl / Bessels.jl`) for a vector of values between 0 and 100. |
123 |
| - |
124 |
| -## Float32 |
125 |
| - |
126 |
| -| function | Relative speed | |
127 |
| -| ------------- | ------------- | |
128 |
| -| besselj0 | 1.7x | |
129 |
| -| besselj1 | 1.7x | |
130 |
| -| bessely0 | 1.6x | |
131 |
| -| bessely1 | 1.6x | |
132 |
| -| besseli0 | 24x | |
133 |
| -| besseli1 | 22x | |
134 |
| -| besselk0 | 13x | |
135 |
| -| besselk1 | 15x | |
136 |
| - |
137 |
| -* it looks like SpecialFunctions.jl doesn't always preserve the correct input type so some of the calculations may be done in Float64. This might skew the benchmarks for `Bessels.jl` as it should have all calculations done in the lower precision. |
| 42 | +These results compare the median value from BenchmarkTools obtained on one machine for arguments between 0 and 100. |
138 | 43 |
|
139 |
| -```julia |
140 |
| -# SpecialFunctions.jl |
141 |
| -julia> @btime besselk(1, x) setup=(x=Float32(10.0*rand())) |
142 |
| - 179.272 ns (1 allocation: 16 bytes) |
143 |
| -0.021948646168061196 # notice incorrect Float64 return type |
| 44 | +We compare the relative sped to implementations provided by [SpecialFunctions.jl](https://github.com/JuliaMath/SpecialFunctions.jl). |
144 | 45 |
|
145 |
| -# Bessels.jl |
146 |
| -julia> @btime besselk1(x) setup=(x=Float32(10.0*rand())) |
147 |
| - 22.967 ns (0 allocations: 0 bytes) |
148 |
| -0.0027777348f0 # notice correct Float32 return type |
149 |
| -``` |
| 46 | +| function | `Float32` | `Float64` |
| 47 | +| ------------- | ------------- | ------------- | |
| 48 | +| besselj0 | 1.7x | 1.8x |
| 49 | +| besselj1 | 1.7x | 1.9x |
| 50 | +| bessely0 | 1.9x | 1.8x |
| 51 | +| bessely1 | 1.7x | 1.7x |
| 52 | +| besseli0 | 26x | 13.2x |
| 53 | +| besseli1 | 22x | 13.9x |
| 54 | +| besseli(20, x) | 5.4x | 2.1x | |
| 55 | +| besseli(120, x) | 6x | 4.5x | |
| 56 | +| besselk0 | 16x | 12.7x |
| 57 | +| besselk1 | 15x | 14.3x |
| 58 | +| besselk(20, x) | 5.4x | 5.7x | |
| 59 | +| besselk(120, x) | 2.9x | 3.4x | |
150 | 60 |
|
151 |
| -## Float64 |
| 61 | +* SpecialFunctions.jl doesn't always preserve the correct input type so some of the calculations may be done in Float64. This might skew the benchmarks for `Bessels.jl`. |
152 | 62 |
|
153 |
| -| function | Relative speed | |
154 |
| -| ------------- | ------------- | |
155 |
| -| besselj0 | 1.7x | |
156 |
| -| besselj1 | 1.9x | |
157 |
| -| bessely0 | 1.5x | |
158 |
| -| bessely1 | 1.5x | |
159 |
| -| besseli0 | 9x | |
160 |
| -| besseli1 | 7x | |
161 |
| -| besselk0 | 5x | |
162 |
| -| besselk1 | 5x | |
| 63 | +# Current Development Plans |
163 | 64 |
|
164 |
| -```julia |
165 |
| -# SpecialFunctions.jl |
166 |
| -julia> @btime besselk(1, x) setup=(x=10.0*rand()) |
167 |
| - 184.726 ns (1 allocation: 16 bytes) # notice the small difference in Float32 and Float64 implementations |
168 |
| -0.0007517428778913419 |
| 65 | +- More robust implementations of `besselj(nu, x)` and `bessely(nu, x)` |
| 66 | +- Support non-integer orders |
| 67 | +- Support complex arguments |
169 | 68 |
|
170 |
| -# Bessels.jl |
171 |
| -julia> @btime besselk1(x) setup=(x=10.0*rand()) |
172 |
| - 47.824 ns (0 allocations: 0 bytes) |
173 |
| -0.0057366790518002045 |
174 |
| -``` |
| 69 | +# Contributing |
| 70 | + |
| 71 | +Contributions are very welcome, as are feature requests and suggestions. Please open an [issue](https://github.com/heltonmc/Bessels.jl/issues/new) for discussion on newer implementations, share papers, new features, or if you encounter any problems. |
| 72 | + |
0 commit comments