Chebyshev polynomials are defined on the interval π₯ β [β1, +1]:
πβ(π₯) = 1 πβ(π₯) = π₯ πβ(π₯) = 2π₯ πβββ(π₯) β πβββ(π₯)
πβ(π₯) = πππ (π ππππ (π₯))
These are orthogonal:
________ / 0 if n != m
β«βββΊΒΉ πβ(π₯)πβ(π₯) / β 1 β π₯Β² ππ₯ = { Ο if n = m = 0
\ Ο/2 if n = m != 0
/ 0 if i != j
β βββα΄Ίβ»ΒΉ πα΅’(π₯β) πβ±Ό(π₯β) = { π if i = j = 0
\ π/2 if i = j != 0
π₯β = πππ ((2π + 1) Ο / (2π)) π = 0, 1, ... , π β 1
This is your secret new superpower! Use it to approximate ππ₯π(βπ₯Β²). How quickly do coefficients of the Chebyshev series vanish?
So far, we have used Chebyshev polynomials of the first kind, πβ(π₯). There are also Chebyshev polynomials of the second kind, πβ(π₯):
πβ(π₯) = 1 πβ(π₯) = π₯ πβ(π₯) = 2π₯ πβββ(π₯) β πβββ(π₯)
πβ(π₯) = 1 πβ(π₯) = 2π₯ πβ(π₯) = 2π₯ πβββ(π₯) β πβββ(π₯)
πβ(π₯) = πππ (π ππππ (π₯)) πβ(π₯) = π ππ((π + 1) ππππ (π₯)) / π ππ(ππππ (π₯))
There are similar orthogonality relations for πβ(π₯) - check a reference. Moreover, there are relations for derivatives and integrals:
(π + 1) πβββ(π₯) β π₯πβ(π₯))
ππβ(π₯)/ππ₯ = π πβββ(π₯) ππβ(π₯)/ππ₯ = -------------------------
(π₯Β² β 1)
πβββ(π₯) πβββ(π₯)
β«πβ(π₯)ππ₯ = --------- - --------- β«πβ(π₯)ππ₯ = πβββ(π₯) / (π + 1)
2 (π + 1) 2 (π β 1)
πβββ(π₯) πβββ(π₯)
β« πβ(π₯) ππ₯ = --------- - ---------
2 (π + 1) 2 (π β 1)
Use your Chebyshev approximation of ππ₯π(βπ₯Β²) to derive the integral of the function.
When this is used for numerical integration of functions, itβs also known as Clenshaw-Curtis quadrature.
You can find the code in C++ in day5-ex1.cxx
.
If you look at the coefficients, every other coefficient is zero because ππ₯π(βπ₯Β²) is an even function. One easy way to deal with this is to exploit this symmetry, and use something like ππ₯π(β(2.5 + 2.5π₯)Β²) for π₯ > 0 instead.
For high precision work, itβs useful to calculate with higher numerical
precision. One could use the long double
data type in C/C++, or use an
arbitary precision floating point library or calculator (like calc,
see day5-ex1.calc
).
In many applications, you need both sin(x) and cos(x) with π₯ β [βΟ, Ο], and you
need it for many different values of x. In the C/C++ standard library, there is
the sincos
function which calculates both simultaneously. Pick one or
more of the following problems:
Whatβs the accuracy and how does speed compare?
Example code can be found in day5-ex2.cxx
.
In the code, we aim for πͺ(10β»β·) precision (although not all algorithms reach it). When compiled with g++ (or clang++), results similar to these can be obtained:
routine | error sin/cos | time/call | time/call |
---|---|---|---|
(g++) [ns] | (clang++) [ns] | ||
libc sin/cos | 0/0 | 20.4 | 32.7 |
Cheb. for π₯β[βΟ,Ο] | 3.6e-7/3.0e-7 | 33.7 | 3.6 |
Cheb. for sin for π₯β[0,Ο] | 3.0e-7/1.9e-4 | 50.1 | 5.4 |
8-fold arg. doubling, Taylor | 8.0e-5/5.6e-5 | 18.7 | 3.3 |
Cheb. for π₯β[0,Ο/2] | 9.5e-7/1.3e-6 | 29.8 | 3.7 |
In the code, we aim for πͺ(10β»β·) precision (although not all algorithms reach it). When compiled with g++ (or clang++), results similar to these can be obtained:
routine | error sin/cos | time/call | time/call |
---|---|---|---|
(g++) [ns] | (clang++) [ns] | ||
libc sin/cos | 0/0 | 20.4 | 32.7 |
Cheb. for π₯β[βΟ,Ο] | 3.6e-7/3.0e-7 | 33.7 | 3.6 |
Cheb. for sin for π₯β[0,Ο] | 3.0e-7/1.9e-4 | 50.1 | 5.4 |
8-fold arg. doubling, Taylor | 8.0e-5/5.6e-5 | 18.7 | 3.3 |
Cheb. for π₯β[0,Ο/2] | 9.5e-7/1.3e-6 | 29.8 | 3.7 |
Observations: