Skip to content

Commit 142e823

Browse files
authored
Merge pull request #31 from heltonmc/update_readme
Update readme
2 parents e3aa934 + be9d79b commit 142e823

File tree

1 file changed

+187
-37
lines changed

1 file changed

+187
-37
lines changed

README.md

Lines changed: 187 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
[![Build Status](https://github.com/heltonmc/Bessels.jl/actions/workflows/CI.yml/badge.svg?branch=master)](https://github.com/heltonmc/Bessels.jl/actions/workflows/CI.yml?query=branch%3Amaster)
33
[![Coverage](https://codecov.io/gh/heltonmc/Bessels.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/heltonmc/Bessels.jl)
44

5-
A Julia implementation of Bessel's functions and modified Bessel's functions of the first and second kind.
5+
Numerical routines for computing Bessel functions and modified Bessel functions of the first and second kind. These routines are written in the Julia programming language and are self contained without any external dependencies.
66

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.
7+
The goal of the library is to provide high quality numerical implementations of Bessel functions with high accuracy without comprimising on computational time. In general, we try to match (and often exceed) the accuracy of other open source routines such as those provided by [SpecialFunctions.jl](https://github.com/JuliaMath/SpecialFunctions.jl). There are instances where we don't quite match that desired accuracy (within a digit or two) but in general will provide implementations that are 5-10x faster (see [benchmarks](https://github.com/heltonmc/Bessels.jl/edit/update_readme/README.md#benchmarks)).
8+
9+
The library currently only supports Bessel functions and modified Bessel functions of the first and second kind for positive real arguments and integer and noninteger orders. Negative arguments are also supported only if the return value is real. We plan to support complex arguments in the future. An unexported gamma function is also provided.
810

911
# Quick start
1012

@@ -14,59 +16,207 @@ pkg> add https://github.com/heltonmc/Bessels.jl.git
1416

1517
julia> using Bessels
1618

17-
# Bessel function of the first kind of order 0
18-
julia> besselj0(1.0)
19-
0.7651976865579665
19+
julia> x = 12.3; nu = 1.3
2020

21-
julia> besselj0(1.0f0)
22-
0.7651977f0
21+
julia> besselj(nu, x)
22+
-0.2267581644816903
2323
```
2424

2525
# Supported functions
2626

27+
### Bessel Functions of the first kind
28+
29+
$$ J_{\nu} = \sum_{m=0}^{\infty} \frac{(-1)^m}{m!\Gamma(m+\nu+1)}(\frac{x}{2})^{2m+\nu} $$
30+
31+
Bessel functions of the first kind, denoted as $J_{\nu}(x)$, can be called with `besselj(nu, x)` where `nu` is the order of the Bessel function with argument `x`. Routines are also available for orders `0` and `1` which can be called with `besselj0(x)` and `besselj1(x)`.
32+
33+
```julia
34+
julia> v, x = 1.4, 12.3
35+
36+
# generic call for any order v
37+
julia> besselj(v, x)
38+
-0.22796228516266664
39+
40+
# v = 0
41+
julia> besselj0(x)
42+
0.11079795030758544
43+
44+
# v = 1
45+
julia> besselj1(x)
46+
-0.1942588480405914
47+
```
48+
49+
### Bessel Functions of the second kind
50+
51+
$$ Y_{\nu} = \frac{J_{\nu} \cos(\nu \pi) - J_{-\nu}}{\sin(\nu \pi)} $$
52+
53+
Bessel functions of the second kind, denoted as $Y_{\nu}(x)$, can be called with `bessely(nu, x)`. Routines are also available for orders `0` and `1` which can be called with `bessely0(x)` and `bessely1(x)`.
54+
55+
```julia
56+
julia> v, x = 1.4, 12.3
57+
58+
# generic call for any order v
59+
julia> bessely(v, x)
60+
0.00911009829832235
61+
62+
# v = 0
63+
julia> bessely0(x)
64+
-0.19859309463502633
65+
66+
# v = 1
67+
julia> bessely1(x)
68+
-0.11894840329926633
69+
```
70+
71+
### Modified Bessel functions of the first kind
72+
73+
$$ I_{\nu} = \sum_{m=0}^{\infty} \frac{1}{m!\Gamma(m+\nu+1)}(\frac{x}{2})^{2m+\nu} $$
74+
75+
Modified Bessel functions of the first kind, denoted as $I_{\nu}(x)$, can be called with `besseli(nu, x)` where `nu` is the order of the Bessel function with argument `x`. Routines are also available for orders `0` and `1` which can be called with `besseli0(x)` and `besseli1`. Exponentially scaled versions of these functions $I_{\nu}(x) * e^{-x}$ are also provided which can be called with `besseli0x(nu, x)`, `besseli1x(nu, x)`, and `besselix(nu, x)`.
76+
77+
```julia
78+
julia> v, x = 1.4, 12.3
79+
80+
# generic call for any order v
81+
julia> besseli(v, x)
82+
23781.28963619158
83+
84+
# exponentially scaled version
85+
julia> besselix(v, x)
86+
0.10824635342651369
87+
88+
# v = 0
89+
julia> besseli0(x)
90+
25257.48759692308
91+
julia> besseli0x(x)
92+
0.11496562932068803
93+
94+
# v = 1
95+
julia> besseli1(x)
96+
24207.933018435186
97+
julia> besseli1x(x)
98+
0.11018832507935208
99+
```
100+
101+
### Modified Bessel Functions of the second kind
102+
103+
$$ K_{\nu} = \frac{\pi}{2} \frac{I_{-\nu} - I_{\nu}}{\sin(\nu \pi)} $$
104+
105+
Modified Bessel functions of the second kind, denoted as $K_{\nu}(x)$, can be called with `besselk(nu, x)`. Routines are available for orders `0` and `1` which can be called with `besselk0(x)` and `besselk1`. Exponentially scaled versions of these functions $K_{\nu}(x) * e^{x}$ are also provided which can be called with `besselk0x(nu, x)`, `besselk1x(nu, x)`, and `besselkx(nu, x)`.
106+
107+
```julia
108+
julia> v, x = 1.4, 12.3
109+
110+
julia> besselk(v, x)
111+
1.739055243080153e-6
112+
113+
julia> besselk0(x)
114+
1.6107849768886856e-6
115+
116+
julia> besselk1(x)
117+
1.6750295538365835e-6
118+
```
119+
120+
### Support for negative arguments
121+
122+
Support is provided for negative arguments and orders only if the return value is real. A domain error will be thrown if the return value is complex. See https://github.com/heltonmc/Bessels.jl/issues/30 for more details.
123+
124+
```julia
125+
julia> (v,x) = 13.0, -1.0
126+
julia> besseli(v,x)
127+
-1.9956316782072008e-14
128+
129+
julia> (v, x) = -14.0, -9.9
130+
julia> besseli(v,x)
131+
0.2892290867115618
132+
133+
julia> (v,x) = 12.6, -3.0
134+
julia> besseli(v,x)
135+
ERROR: DomainError with -3.0:
136+
Complex result returned for real arguments. Complex arguments are currently not supported
137+
Stacktrace:
138+
[1] besseli(nu::Float64, x::Float64)
139+
@ Bessels ~/Documents/code/repos/Bessels.jl/src/besseli.jl:176
140+
[2] top-level scope
141+
@ REPL[9]:1
142+
```
143+
#### Gamma
144+
We also provide an unexported gamma function for real arguments that can be called with `Bessels.gamma(x)`.
145+
146+
# Accuracy
147+
148+
We report the relative errors (`abs(1 - Bessels.f(x)/ArbNumerics.f(ArbFloat(x)))`) compared to `ArbNumerics.jl` when computed in a higher precision. The working precision was set to `setworkingprecision(ArbFloat, 500); setextrabits(128)` for the calculations in arbitrary precision. We generate a thousand random points for $x \in (0, 100)$ and compute the mean and maximum absolute relative errors.
149+
150+
151+
| function | `mean` | `maximum`
152+
| ------------- | ------------- | ------------- |
153+
| besselj0(x) | 3e-16 | 6e-14 |
154+
| besselj1(x) | 2e-15 | 7e-13 |
155+
| besselj(5.0, x) | 3e-14 | 2e-11 |
156+
| besselj(12.8, x) | 2e-14 | 2e-12 |
157+
| besselj(111.6, x) | 8e-15 | 4e-14 |
158+
| bessely0(x) | 2e-15 | 5e-13 |
159+
| bessely1(x) | 1e-15 | 2e-13 |
160+
| bessely(4.0, x) | 3e-15 | 2e-12 |
161+
| bessely(6.92, x) | 3e-14 | 5e-12 |
162+
| bessely(113.92, x) | 8e-15 | 8e-14 |
163+
| besselk0(x) | 1.2e-16 | 4e-16 |
164+
| besselk1(x) | 1.2e-16 | 5e-16 |
165+
| besselk(14.0, x) | 4e-15 | 3e-14 |
166+
| besselk(27.32, x) | 6e-15 | 3e-14 |
167+
| besseli0(x) | 1.5e-16 | 6e-16 |
168+
| besseli1(x) | 1.5e-16 | 5e-16 |
169+
| besseli(9.0, x) | 2e-16 | 2e-15 |
170+
| besseli(92.12, x) | 9e-15 | 7e-14 |
171+
| Bessels.gamma(x) | 1.3e-16 | 5e-16
172+
173+
174+
In general the largest relative errors are observed near the zeros of Bessel functions for `besselj` and `bessely`. Accuracy might also be slightly worse for very large arguments when using `Float64` precision.
175+
176+
# Benchmarks
177+
178+
We give brief performance comparisons to the implementations provided by [SpecialFunctions.jl](https://github.com/JuliaMath/SpecialFunctions.jl). In general, special functions are computed with separate algorithms in different domains leading to computational time being dependent on argument. For these comparisons we show the relative speed increase for computing random values between `0` and `100` for `x` and order `nu`. In some ranges, performance may be significantly better while others more similar.
179+
180+
| function | `Float64`
181+
| ------------- | ------------- |
182+
| besselj0(x) | 2.5x
183+
| besselj(nu, x) | 6x
184+
| bessely0(x) | 2.3x
185+
| bessely(nu, x) | 5x
186+
| besseli0 | 10x
187+
| besseli(nu, x) | 7x |
188+
| besselk0 | 10x
189+
| besselk(nu, x) | 4x |
190+
| Bessels.gamma(x) | 5x |
191+
192+
193+
Benchmarks were run using Julia Version 1.7.2 on an Apple M1 using Rosetta.
194+
195+
# API
196+
27197
- `besselj0(x)`
28198
- `besselj1(x)`
199+
- `besselj(nu, x)`
29200
- `bessely0(x)`
30201
- `bessely1(x)`
202+
- `bessely(nu, x)`
31203
- `besseli0(x)`
32204
- `besseli1(x)`
205+
- `besseli(nu, x)`
33206
- `besselk0(x)`
34207
- `besselk1(x)`
35-
- `besseli(nu, x)`
36208
- `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-
40-
# Benchmarks
41-
42-
These results compare the median value from BenchmarkTools obtained on one machine for arguments between 0 and 100.
43-
44-
We compare the relative [speed](https://github.com/heltonmc/Bessels.jl/blob/master/benchmark/benchmark.jl) to implementations provided by [SpecialFunctions.jl](https://github.com/JuliaMath/SpecialFunctions.jl).
45-
46-
| function | `Float32` | `Float64`
47-
| ------------- | ------------- | ------------- |
48-
| besselj0 | 1.7x | 3.1x
49-
| besselj1 | 1.7x | 3.0x
50-
| bessely0 | 1.9x | 2.7x
51-
| bessely1 | 1.7x | 2.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 |
60-
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`.
209+
- `Bessels.gamma(x)`
62210

63211
# Current Development Plans
64212

65-
- More robust implementations of `besselj(nu, x)` and `bessely(nu, x)`
66-
- Support non-integer orders
67-
- Support complex arguments
213+
- Support for higher precision `Double64`, `Float128`
214+
- Hankel functions
215+
- Support for complex arguments (`x` and `nu`)
216+
- Airy functions
217+
- Support for derivatives with respect to argument and order
68218

69219
# Contributing
70220

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.
221+
Contributions are very welcome, as are feature requests, suggestions or general discussions. 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. Our goal is to provide high quality implementations of Bessel functions that match or exceed the accuracy of the implementatations provided by SpecialFunctions.jl. Please let us know if you encounter any accuracy or performance differences.
72222

0 commit comments

Comments
 (0)