use scirs2_special::{
beta, betaln, digamma, ellipe, ellipk, erf, erfc, erfinv, gamma, gammaln, i0, j0, j1, jn, k0,
y0, y1,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== SciRS2 Special Functions Tutorial ===\n");
section_gamma()?;
section_bessel()?;
section_error_functions()?;
section_elliptic()?;
println!("\n=== Tutorial Complete ===");
Ok(())
}
fn section_gamma() -> Result<(), Box<dyn std::error::Error>> {
println!("--- 1. Gamma Function Family ---\n");
println!("Gamma function (generalized factorial):");
println!(" gamma(1) = {:.6} (0! = 1)", gamma(1.0_f64));
println!(" gamma(2) = {:.6} (1! = 1)", gamma(2.0_f64));
println!(" gamma(5) = {:.6} (4! = 24)", gamma(5.0_f64));
println!(
" gamma(0.5) = {:.6} (sqrt(pi) = {:.6})",
gamma(0.5_f64),
std::f64::consts::PI.sqrt()
);
println!();
println!("Log-gamma (for large values):");
println!(" gammaln(100) = {:.6}", gammaln(100.0_f64));
println!(" gammaln(1000) = {:.6}", gammaln(1000.0_f64));
println!();
println!("Digamma function psi(x):");
println!(
" digamma(1) = {:.6} (-euler_gamma = {:.6})",
digamma(1.0_f64),
-0.5772156649
);
println!(" digamma(2) = {:.6} (1 - euler_gamma)", digamma(2.0_f64));
println!();
println!("Beta function B(a,b):");
println!(
" beta(2, 3) = {:.6} (1/12 = {:.6})",
beta(2.0_f64, 3.0_f64),
1.0 / 12.0
);
println!(
" beta(0.5, 0.5) = {:.6} (pi = {:.6})",
beta(0.5_f64, 0.5_f64),
std::f64::consts::PI
);
println!(" betaln(100, 200) = {:.6}", betaln(100.0_f64, 200.0_f64));
println!();
Ok(())
}
fn section_bessel() -> Result<(), Box<dyn std::error::Error>> {
println!("--- 2. Bessel Functions ---\n");
println!("Bessel functions of the first kind J_n(x):");
let x_vals = [0.0, 1.0, 2.0, 5.0, 10.0];
println!(" x J0(x) J1(x) J2(x)");
println!(" ------- ----------- ----------- -----------");
for &x in &x_vals {
println!(
" {:<7.1} {:<11.6} {:<11.6} {:<11.6}",
x,
j0(x),
j1(x),
jn(2, x)
);
}
println!();
println!("Bessel functions of the second kind Y_n(x):");
let x_vals_y = [0.5, 1.0, 2.0, 5.0, 10.0];
println!(" x Y0(x) Y1(x)");
println!(" ------- ----------- -----------");
for &x in &x_vals_y {
println!(" {:<7.1} {:<11.6} {:<11.6}", x, y0(x), y1(x));
}
println!();
println!("Modified Bessel functions:");
println!(" I0(1.0) = {:.6}", i0(1.0_f64));
println!(" K0(1.0) = {:.6}", k0(1.0_f64));
println!();
Ok(())
}
fn section_error_functions() -> Result<(), Box<dyn std::error::Error>> {
println!("--- 3. Error Functions ---\n");
println!("Error function erf(x):");
let x_vals = [0.0, 0.5, 1.0, 1.5, 2.0, 3.0];
for &x in &x_vals {
println!(" erf({:.1}) = {:.8}", x, erf(x));
}
println!();
println!("Complementary error function erfc(x):");
println!(" erfc(0) = {:.8}", erfc(0.0_f64));
println!(" erfc(1) = {:.8}", erfc(1.0_f64));
println!(" erfc(3) = {:.2e} (very small)", erfc(3.0_f64));
println!(" erfc(5) = {:.2e} (even smaller)", erfc(5.0_f64));
println!();
println!("Inverse error function:");
println!(" erfinv(0.0) = {:.6}", erfinv(0.0_f64));
println!(" erfinv(0.5) = {:.6}", erfinv(0.5_f64));
println!(" erfinv(0.95) = {:.6}", erfinv(0.95_f64));
let x = 1.96_f64;
let normal_cdf = 0.5 * (1.0 + erf(x / 2.0_f64.sqrt()));
println!("\n Normal CDF via erf:");
println!(
" CDF(1.96) = 0.5 * (1 + erf(1.96/sqrt(2))) = {:.6}",
normal_cdf
);
println!(" (This is the 97.5th percentile)\n");
Ok(())
}
fn section_elliptic() -> Result<(), Box<dyn std::error::Error>> {
println!("--- 4. Elliptic Integrals ---\n");
println!("Complete elliptic integral K(m):");
let m_vals = [0.0, 0.25, 0.5, 0.75, 0.9, 0.99];
for &m in &m_vals {
println!(" K({:.2}) = {:.8}", m, ellipk(m));
}
println!(" K(0) = pi/2 = {:.8}", std::f64::consts::PI / 2.0);
println!(" (K(m) -> infinity as m -> 1)\n");
println!("Complete elliptic integral E(m):");
for &m in &m_vals {
println!(" E({:.2}) = {:.8}", m, ellipe(m));
}
println!(" E(0) = pi/2 = {:.8}", std::f64::consts::PI / 2.0);
println!(" E(1) = 1.0\n");
let l = 1.0_f64; let g = 9.81_f64; let theta_max = 0.1_f64; let m_pend = (theta_max / 2.0).sin().powi(2);
let period = 4.0 * (l / g).sqrt() * ellipk(m_pend);
let period_approx = 2.0 * std::f64::consts::PI * (l / g).sqrt();
println!("Pendulum period (L=1m, theta_max=0.1 rad):");
println!(" Exact: T = {:.6} s", period);
println!(" Small-angle: T = {:.6} s", period_approx);
println!(" Difference: {:.6} s\n", (period - period_approx).abs());
Ok(())
}