Expand description
microcheby is a crate for computing and evaluating polynomial approximations
of functions of one variable using using Chebyshev polynomials.
The code is no_std compatible, does not depend on alloc and is optimized for resource
constrained environments where every clock cycle counts. Optimizations include:
- Clenshaw recursion for evaluating approximations.
- Efficient loop free functions for evaluating low order approximations.
- Even more efficient loop free evaluation if the range happens to be [-1, 1].
- Approximation evaluation without divisions.
§Installing
Add the following line to your Cargo.toml file:
microcheby = "0.1"To use microcheby in a no_std environment:
microcheby = { version = "0.1", default-features = false }§Chebyshev approximation
Sufficiently well behaved functions can be expressed as an infinite weighted sum of so called Chebyshev polynomials of increasing order. Such a sum is known as a Chebyshev expansion. If the target function is smooth enough, the coefficients (weights) of the expansion will typically converge to zero quickly and only the first few terms are needed to get a good approximation. For a truncated expansion with n terms, an estimate of the approximation error is given by the magnitude of coefficient n+1.
For a more detailed introduction, see 5.8 Chebyshev Approximation in Numerical Recipes in C: The Art of Scientific Computing.
§Basic usage
use microcheby::ChebyshevExpansion;
// Compute a 6 term expansion approximating the square root of x on the interval [0.1, 1.0]
let sqrt_exp = ChebyshevExpansion::<6>::fit(0.1, 1.0, |x| x.sqrt());
// Get the approximated value at x=0.7
let value_approx = sqrt_exp.eval(0.7);
// Get the actual value at x=0.7
let value_actual = 0.7_f32.sqrt();
// Compute the approximation error
let error = value_actual - value_approx;
assert!(error.abs() < 0.0002);§Precomputing and instantiating expansions
Computing expansion coefficients requires an accurate cosine function and potentially costly target function evaluations, so it is sometimes desirable to precompute the coefficients and then use them to instantiate the expansion.
use microcheby::ChebyshevExpansion;
// Compute a 6 term expansion approximating the square root of x on the interval [0.1, 1.0]
let sqrt_exp = ChebyshevExpansion::<6>::fit(0.1, 1.0, |x| x.sqrt());
// x_min, x_max and coeffs are needed to instantiate the expansion.
// You can either print them to the terminal like this or use the associated getters.
println!("{sqrt_exp}");
// Instantiate the expansion computed above using arguments copied from the terminal.
let exp = ChebyshevExpansion::new(
0.1,
1.0,
[1.4066492, 0.32991815, -0.04125017, 0.010474294, -0.0032901317, 0.0010244437]
);
assert_eq!(sqrt_exp.x_min(), exp.x_min());
assert_eq!(sqrt_exp.x_max(), exp.x_max());
assert_eq!(sqrt_exp.coeffs(), exp.coeffs());Expansions can also be instantiated statically at compile time.
use microcheby::ChebyshevExpansion;
// Compute a 6 term expansion approximating the square root of x on the interval [0.1, 1.0]
let sqrt_exp = ChebyshevExpansion::<6>::fit(0.1, 1.0, |x| x.sqrt());
// x_min, range_scale and coeffs_internal are needed to instantiate the expansion
// at compile time since floating point operations are not allowed in constant expressions.
// You can either print them to the terminal like this or get them using a debugger.
println!("{:?}", sqrt_exp);
// A statically allocated ChebyshevExpansion
const EXP:ChebyshevExpansion<6> = ChebyshevExpansion::const_new(
0.1,
4.4444447,
[0.7033246, 0.32991815, -0.04125017, 0.010474294, -0.0032901317, 0.0010244437]
);
assert_eq!(sqrt_exp.x_min(), EXP.x_min());
assert_eq!(sqrt_exp.x_max(), EXP.x_max());
assert_eq!(sqrt_exp.coeffs(), EXP.coeffs());Structs§
- Chebyshev
Expansion - An N term Chebyshev expansion. See 5.8 Chebyshev Approximation in Numerical Recipes in C: The Art of Scientific Computing.
Enums§
- Match
Boundary - Boundary matching is the process of adding a linear
term ax + b to the Chebyshev expansion to make the it
match the original function exactly at
x_minand/orx_max. This probably increases the approximation error, but can be useful when exact matches atx_minand/orx_maxare more important than overall accuracy.