use scirs2_core::numeric::{Float, FromPrimitive};
use std::fmt::Debug;
const AIRY_TABLE: [(f64, f64, f64, f64, f64); 13] = [
(
-5.0,
0.3507610090241142,
0.7845177219792484,
0.3757289802157,
-0.7771388142155,
),
(
-4.0,
0.3818263073159224,
0.5251967358889706,
0.1475403876463545,
0.5609353889057985,
),
(
-3.0,
0.3786287733679269,
0.1297506195662909,
-0.1982693379014283,
0.5924485964250711,
),
(
-2.0,
0.22740742820168557,
0.18836677954676762,
0.37339167942543735,
-0.13289576834890213,
),
(
-1.0,
0.5355608832923521,
-0.3271928185544436,
0.103_997_389_496_944_6,
0.5383830805628176,
),
(
0.0,
0.3550280538878172,
-0.25881940379280678,
0.6149266274460007,
0.4482883573538264,
),
(
0.5,
0.2309493905707306,
-0.2241595309561765,
0.8712188886443742,
0.6820309552208995,
),
(
1.0,
0.1352924163128814,
-0.16049975743698353,
1.2074235949528715,
1.0434774887138,
),
(
2.0,
0.03492413042327235,
-0.06120049354097896,
3.5424680997112654,
3.3662351522409107,
),
(
3.0,
0.006591139357460388,
-0.01585408416342784,
10.139198841026192,
12.469524135390914,
),
(
4.0,
0.0009074603677222401,
-0.002683279352261441,
29.819025046218183,
44.94308396859953,
),
(
5.0,
0.0001083277795169,
-0.0003280924942020832,
83.73823961011828,
148.34022202713066,
),
(
10.0,
1.1047532368598592e-10,
-3.3630442265728913e-10,
14036.271985859755,
44387.26986072647,
),
];
#[allow(dead_code)]
pub fn ai<F: Float + FromPrimitive + Debug>(x: F) -> F {
let x_f64 = x.to_f64().expect("Operation failed");
if x_f64 > 10.0 {
let z = (2.0 / 3.0) * x_f64.powf(1.5);
let prefactor = 1.0 / (2.0 * std::f64::consts::PI.sqrt() * x_f64.powf(0.25));
return F::from(prefactor * (-z).exp()).expect("Operation failed");
}
if x_f64 < -5.0 {
let z = (2.0 / 3.0) * (-x_f64).powf(1.5);
let pi_quarter = std::f64::consts::FRAC_PI_4;
let prefactor = 1.0 / (std::f64::consts::PI.sqrt() * (-x_f64).powf(0.25));
return F::from(prefactor * (z - pi_quarter).sin()).expect("Operation failed");
}
let mut idx_low = 0;
for i in 0..AIRY_TABLE.len() - 1 {
if x_f64 >= AIRY_TABLE[i].0 && x_f64 <= AIRY_TABLE[i + 1].0 {
idx_low = i;
break;
}
}
let x0 = AIRY_TABLE[idx_low].0;
let x1 = AIRY_TABLE[idx_low + 1].0;
let y0 = AIRY_TABLE[idx_low].1; let y1 = AIRY_TABLE[idx_low + 1].1;
let result = y0 + (x_f64 - x0) * (y1 - y0) / (x1 - x0);
F::from(result).expect("Failed to convert to float")
}
#[allow(dead_code)]
pub fn aip<F: Float + FromPrimitive + Debug>(x: F) -> F {
let x_f64 = x.to_f64().expect("Operation failed");
if x_f64 > 10.0 {
let z = (2.0 / 3.0) * x_f64.powf(1.5);
let prefactor = -x_f64.sqrt() / (2.0 * std::f64::consts::PI.sqrt() * x_f64.powf(0.25));
return F::from(prefactor * (-z).exp()).expect("Operation failed");
}
if x_f64 < -5.0 {
let z = (2.0 / 3.0) * (-x_f64).powf(1.5);
let pi_quarter = std::f64::consts::FRAC_PI_4;
let prefactor = (-x_f64).sqrt() / (std::f64::consts::PI.sqrt() * (-x_f64).powf(0.25));
return F::from(prefactor * (z - pi_quarter).cos()).expect("Operation failed");
}
let mut idx_low = 0;
for i in 0..AIRY_TABLE.len() - 1 {
if x_f64 >= AIRY_TABLE[i].0 && x_f64 <= AIRY_TABLE[i + 1].0 {
idx_low = i;
break;
}
}
let x0 = AIRY_TABLE[idx_low].0;
let x1 = AIRY_TABLE[idx_low + 1].0;
let y0 = AIRY_TABLE[idx_low].2; let y1 = AIRY_TABLE[idx_low + 1].2;
let result = y0 + (x_f64 - x0) * (y1 - y0) / (x1 - x0);
F::from(result).expect("Failed to convert to float")
}
#[allow(dead_code)]
pub fn bi<F: Float + FromPrimitive + Debug>(x: F) -> F {
let x_f64 = x.to_f64().expect("Operation failed");
if x_f64 > 10.0 {
let z = (2.0 / 3.0) * x_f64.powf(1.5);
let prefactor = 1.0 / (std::f64::consts::PI.sqrt() * x_f64.powf(0.25));
return F::from(prefactor * z.exp()).expect("Operation failed");
}
if x_f64 < -5.0 {
let z = (2.0 / 3.0) * (-x_f64).powf(1.5);
let pi_quarter = std::f64::consts::FRAC_PI_4;
let prefactor = 1.0 / (std::f64::consts::PI.sqrt() * (-x_f64).powf(0.25));
return F::from(prefactor * (z - pi_quarter).cos()).expect("Operation failed");
}
let mut idx_low = 0;
for i in 0..AIRY_TABLE.len() - 1 {
if x_f64 >= AIRY_TABLE[i].0 && x_f64 <= AIRY_TABLE[i + 1].0 {
idx_low = i;
break;
}
}
let x0 = AIRY_TABLE[idx_low].0;
let x1 = AIRY_TABLE[idx_low + 1].0;
let y0 = AIRY_TABLE[idx_low].3; let y1 = AIRY_TABLE[idx_low + 1].3;
let result = y0 + (x_f64 - x0) * (y1 - y0) / (x1 - x0);
F::from(result).expect("Failed to convert to float")
}
#[allow(dead_code)]
pub fn bip<F: Float + FromPrimitive + Debug>(x: F) -> F {
let x_f64 = x.to_f64().expect("Operation failed");
if x_f64 > 10.0 {
let z = (2.0 / 3.0) * x_f64.powf(1.5);
let prefactor = x_f64.sqrt() / (std::f64::consts::PI.sqrt() * x_f64.powf(0.25));
return F::from(prefactor * z.exp()).expect("Operation failed");
}
if x_f64 < -5.0 {
let z = (2.0 / 3.0) * (-x_f64).powf(1.5);
let pi_quarter = std::f64::consts::FRAC_PI_4;
let prefactor = (-x_f64).sqrt() / (std::f64::consts::PI.sqrt() * (-x_f64).powf(0.25));
return F::from(-prefactor * (z - pi_quarter).sin()).expect("Operation failed");
}
let mut idx_low = 0;
for i in 0..AIRY_TABLE.len() - 1 {
if x_f64 >= AIRY_TABLE[i].0 && x_f64 <= AIRY_TABLE[i + 1].0 {
idx_low = i;
break;
}
}
let x0 = AIRY_TABLE[idx_low].0;
let x1 = AIRY_TABLE[idx_low + 1].0;
let y0 = AIRY_TABLE[idx_low].4; let y1 = AIRY_TABLE[idx_low + 1].4;
let result = y0 + (x_f64 - x0) * (y1 - y0) / (x1 - x0);
F::from(result).expect("Failed to convert to float")
}
pub mod complex {
use scirs2_core::numeric::Complex64;
use std::f64::consts::PI;
pub fn ai_complex(z: Complex64) -> Complex64 {
if z.im.abs() < 1e-15 {
let real_result = super::ai(z.re);
return Complex64::new(real_result, 0.0);
}
if z.norm() == 0.0 {
return Complex64::new(0.3550280538878172, 0.0); }
if z.norm() < 8.0 {
return ai_series_complex(z);
}
ai_asymptotic_complex(z)
}
pub fn aip_complex(z: Complex64) -> Complex64 {
if z.im.abs() < 1e-15 {
let real_result = super::aip(z.re);
return Complex64::new(real_result, 0.0);
}
if z.norm() == 0.0 {
return Complex64::new(-0.25881940379280678, 0.0); }
if z.norm() < 8.0 {
return aip_series_complex(z);
}
aip_asymptotic_complex(z)
}
pub fn bi_complex(z: Complex64) -> Complex64 {
if z.im.abs() < 1e-15 {
let real_result = super::bi(z.re);
return Complex64::new(real_result, 0.0);
}
if z.norm() == 0.0 {
return Complex64::new(0.6149266274460007, 0.0); }
if z.norm() < 8.0 {
return bi_series_complex(z);
}
bi_asymptotic_complex(z)
}
pub fn bip_complex(z: Complex64) -> Complex64 {
if z.im.abs() < 1e-15 {
let real_result = super::bip(z.re);
return Complex64::new(real_result, 0.0);
}
if z.norm() == 0.0 {
return Complex64::new(0.4482883573538264, 0.0); }
if z.norm() < 8.0 {
return bip_series_complex(z);
}
bip_asymptotic_complex(z)
}
fn ai_series_complex(z: Complex64) -> Complex64 {
let c1 = 0.3550280538878172; let c2 = 0.25881940379280678;
let f_z = airy_f_series(z);
let g_z = airy_g_series(z);
Complex64::new(c1, 0.0) * f_z - Complex64::new(c2, 0.0) * g_z
}
fn aip_series_complex(z: Complex64) -> Complex64 {
let c1 = 0.3550280538878172; let c2 = 0.25881940379280678;
let fp_z = airy_fp_series(z);
let gp_z = airy_gp_series(z);
-Complex64::new(c1, 0.0) * fp_z + Complex64::new(c2, 0.0) * gp_z
}
fn bi_series_complex(z: Complex64) -> Complex64 {
let sqrt3 = 3.0_f64.sqrt();
let c1 = 0.3550280538878172; let c2 = 0.25881940379280678;
let f_z = airy_f_series(z);
let g_z = airy_g_series(z);
Complex64::new(sqrt3, 0.0) * (Complex64::new(c1, 0.0) * f_z + Complex64::new(c2, 0.0) * g_z)
}
fn bip_series_complex(z: Complex64) -> Complex64 {
let sqrt3 = 3.0_f64.sqrt();
let c1 = 0.3550280538878172; let c2 = 0.25881940379280678;
let fp_z = airy_fp_series(z);
let gp_z = airy_gp_series(z);
Complex64::new(sqrt3, 0.0)
* (-Complex64::new(c1, 0.0) * fp_z + Complex64::new(c2, 0.0) * gp_z)
}
fn airy_f_series(z: Complex64) -> Complex64 {
let mut result = Complex64::new(1.0, 0.0);
let z3 = z * z * z;
let mut term = z3 / Complex64::new(6.0, 0.0);
result += term;
for n in 2..=50 {
term *= z3 / Complex64::new((3 * n * (3 * n - 1) * (3 * n - 2)) as f64, 0.0);
result += term;
if term.norm() < 1e-15 * result.norm() {
break;
}
}
result
}
fn airy_g_series(z: Complex64) -> Complex64 {
let mut result = z;
let z3 = z * z * z;
let mut term = z * z3 / Complex64::new(12.0, 0.0);
result += term;
for n in 2..=50 {
term *= z3 / Complex64::new(((3 * n + 1) * (3 * n) * (3 * n - 1)) as f64, 0.0);
result += term;
if term.norm() < 1e-15 * result.norm() {
break;
}
}
result
}
fn airy_fp_series(z: Complex64) -> Complex64 {
let mut result = z * z / Complex64::new(2.0, 0.0);
let z3 = z * z * z;
let mut term = z * z * z3 / Complex64::new(60.0, 0.0);
result += term;
for n in 2..=50 {
term *= z3 / Complex64::new(((3 * n + 2) * (3 * n + 1) * (3 * n)) as f64, 0.0);
result += term;
if term.norm() < 1e-15 * result.norm() {
break;
}
}
result
}
fn airy_gp_series(z: Complex64) -> Complex64 {
let mut result = Complex64::new(1.0, 0.0);
let z3 = z * z * z;
let mut term = z3 / Complex64::new(3.0, 0.0);
result += term;
for n in 2..=50 {
term *= z3 / Complex64::new(((3 * n - 1) * (3 * n - 2) * (3 * n - 3)) as f64, 0.0);
result += term;
if term.norm() < 1e-15 * result.norm() {
break;
}
}
result
}
fn ai_asymptotic_complex(z: Complex64) -> Complex64 {
let zeta = (2.0 / 3.0) * z.powf(1.5);
let arg_z = z.arg();
if arg_z.abs() < PI / 3.0 {
let prefactor = 1.0 / (2.0 * PI.sqrt() * z.powf(0.25));
prefactor * (-zeta).exp()
} else if arg_z.abs() > 2.0 * PI / 3.0 {
let prefactor = 1.0 / (PI.sqrt() * (-z).powf(0.25));
let phase = zeta - Complex64::new(PI / 4.0, 0.0);
prefactor * phase.sin()
} else {
ai_transition_region(z)
}
}
fn aip_asymptotic_complex(z: Complex64) -> Complex64 {
let zeta = (2.0 / 3.0) * z.powf(1.5);
let arg_z = z.arg();
if arg_z.abs() < PI / 3.0 {
let prefactor = -z.powf(0.25) / (2.0 * PI.sqrt());
prefactor * (-zeta).exp()
} else if arg_z.abs() > 2.0 * PI / 3.0 {
let prefactor = (-z).powf(0.25) / PI.sqrt();
let phase = zeta - Complex64::new(PI / 4.0, 0.0);
prefactor * phase.cos()
} else {
aip_transition_region(z)
}
}
fn bi_asymptotic_complex(z: Complex64) -> Complex64 {
let zeta = (2.0 / 3.0) * z.powf(1.5);
let arg_z = z.arg();
if arg_z.abs() < PI / 3.0 {
let prefactor = 1.0 / (PI.sqrt() * z.powf(0.25));
prefactor * zeta.exp()
} else if arg_z.abs() > 2.0 * PI / 3.0 {
let prefactor = 1.0 / (PI.sqrt() * (-z).powf(0.25));
let phase = zeta - Complex64::new(PI / 4.0, 0.0);
prefactor * phase.cos()
} else {
bi_transition_region(z)
}
}
fn bip_asymptotic_complex(z: Complex64) -> Complex64 {
let zeta = (2.0 / 3.0) * z.powf(1.5);
let arg_z = z.arg();
if arg_z.abs() < PI / 3.0 {
let prefactor = z.powf(0.25) / PI.sqrt();
prefactor * zeta.exp()
} else if arg_z.abs() > 2.0 * PI / 3.0 {
let prefactor = -(-z).powf(0.25) / PI.sqrt();
let phase = zeta - Complex64::new(PI / 4.0, 0.0);
prefactor * phase.sin()
} else {
bip_transition_region(z)
}
}
fn ai_transition_region(z: Complex64) -> Complex64 {
ai_series_complex(z)
}
fn aip_transition_region(z: Complex64) -> Complex64 {
aip_series_complex(z)
}
fn bi_transition_region(z: Complex64) -> Complex64 {
bi_series_complex(z)
}
fn bip_transition_region(z: Complex64) -> Complex64 {
bip_series_complex(z)
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_ai_complex_real_values() {
let test_values = [0.0, 1.0, 2.0, -1.0, -2.0];
for &x in &test_values {
let z = Complex64::new(x, 0.0);
let complex_result = ai_complex(z);
let real_result = super::super::ai(x);
assert_relative_eq!(complex_result.re, real_result, epsilon = 1e-10);
assert!(complex_result.im.abs() < 1e-12);
}
}
#[test]
fn test_aip_complex_real_values() {
let test_values = [0.0, 1.0, 2.0, -1.0, -2.0];
for &x in &test_values {
let z = Complex64::new(x, 0.0);
let complex_result = aip_complex(z);
let real_result = super::super::aip(x);
assert_relative_eq!(complex_result.re, real_result, epsilon = 1e-10);
assert!(complex_result.im.abs() < 1e-12);
}
}
#[test]
fn test_bi_complex_real_values() {
let test_values = [0.0, 1.0, 2.0, -1.0, -2.0];
for &x in &test_values {
let z = Complex64::new(x, 0.0);
let complex_result = bi_complex(z);
let real_result = super::super::bi(x);
assert_relative_eq!(complex_result.re, real_result, epsilon = 1e-10);
assert!(complex_result.im.abs() < 1e-12);
}
}
#[test]
fn test_bip_complex_real_values() {
let test_values = [0.0, 1.0, 2.0, -1.0, -2.0];
for &x in &test_values {
let z = Complex64::new(x, 0.0);
let complex_result = bip_complex(z);
let real_result = super::super::bip(x);
assert_relative_eq!(complex_result.re, real_result, epsilon = 1e-10);
assert!(complex_result.im.abs() < 1e-12);
}
}
#[test]
fn test_airy_differential_equation() {
let test_values = [Complex64::new(1.0, 0.0), Complex64::new(0.5, 0.0)];
for &z in &test_values {
let ai_z = ai_complex(z);
let h = 1e-5; let aip_z_plus = aip_complex(z + Complex64::new(h, 0.0));
let aip_zminus = aip_complex(z - Complex64::new(h, 0.0));
let aipp_z = (aip_z_plus - aip_zminus) / Complex64::new(2.0 * h, 0.0);
let residual = aipp_z - z * ai_z;
assert!(residual.norm() < 0.1); }
}
#[test]
fn test_wronskian_identity() {
let test_values = [Complex64::new(1.0, 0.0), Complex64::new(2.0, 0.0)];
for &z in &test_values {
let ai_z = ai_complex(z);
let aip_z = aip_complex(z);
let bi_z = bi_complex(z);
let bip_z = bip_complex(z);
let wronskian = ai_z * bip_z - aip_z * bi_z;
let expected = Complex64::new(1.0 / PI, 0.0);
assert_relative_eq!(wronskian.re, expected.re, epsilon = 1e-1);
assert!(wronskian.im.abs() < 1e-1);
}
}
}
}
#[allow(dead_code)]
pub fn aie<F: Float + FromPrimitive + Debug>(x: F) -> F {
if x >= F::zero() {
let two_thirds = F::from_f64(2.0 / 3.0).expect("Operation failed");
let exp_factor = (two_thirds * x.powf(F::from_f64(1.5).expect("Operation failed"))).exp();
ai(x) * exp_factor
} else {
ai(x)
}
}
#[allow(dead_code)]
pub fn bie<F: Float + FromPrimitive + Debug>(x: F) -> F {
if x >= F::zero() {
let two_thirds = F::from_f64(2.0 / 3.0).expect("Operation failed");
let exp_factor = (-two_thirds * x.powf(F::from_f64(1.5).expect("Operation failed"))).exp();
bi(x) * exp_factor
} else {
bi(x)
}
}
#[allow(dead_code)]
pub fn airye<F: Float + FromPrimitive + Debug>(x: F) -> (F, F, F, F) {
if x >= F::zero() {
let two_thirds = F::from_f64(2.0 / 3.0).expect("Operation failed");
let exp_factor = (two_thirds * x.powf(F::from_f64(1.5).expect("Operation failed"))).exp();
(
ai(x) * exp_factor,
aip(x) * exp_factor,
bi(x) * (-two_thirds * x.powf(F::from_f64(1.5).expect("Operation failed"))).exp(),
bip(x) * (-two_thirds * x.powf(F::from_f64(1.5).expect("Operation failed"))).exp(),
)
} else {
(ai(x), aip(x), bi(x), bip(x))
}
}
#[allow(dead_code)]
pub fn ai_zeros<F: Float + FromPrimitive + Debug>(k: usize) -> crate::SpecialResult<F> {
use crate::error::SpecialError;
if k == 0 {
return Err(SpecialError::ValueError(
"ai_zeros: k must be >= 1".to_string(),
));
}
if let Some(known_zero) = match k {
1 => Some(-2.338_107_410_459_767),
2 => Some(-4.087_949_444_130_97),
3 => Some(-5.520_559_828_095_551),
4 => Some(-6.786_708_090_071_759),
5 => Some(-7.944_133_587_120_853),
_ => None,
} {
return Ok(F::from_f64(known_zero).expect("Operation failed"));
}
let k_f = F::from_usize(k).expect("Operation failed");
let pi = F::from_f64(std::f64::consts::PI).expect("Operation failed");
let three_fourths = F::from_f64(0.75).expect("Operation failed");
let s = (three_fourths * (k_f - F::from_f64(0.25).expect("Operation failed")) * pi)
.powf(F::from_f64(2.0 / 3.0).expect("Operation failed"));
let initial_guess = -s;
let mut zero = initial_guess;
for _ in 0..20 {
let f_val = ai(zero);
let fp_val = aip(zero);
if fp_val.abs() < F::epsilon() {
break;
}
let correction = f_val / fp_val;
zero = zero - correction;
if correction.abs() < F::from_f64(1e-12).expect("Operation failed") {
break;
}
}
if zero > F::zero() {
return Err(SpecialError::ValueError(
"ai_zeros: failed to converge to negative zero".to_string(),
));
}
Ok(zero)
}
#[allow(dead_code)]
pub fn bi_zeros<F: Float + FromPrimitive + Debug>(k: usize) -> crate::SpecialResult<F> {
use crate::error::SpecialError;
if k == 0 {
return Err(SpecialError::ValueError(
"bi_zeros: k must be >= 1".to_string(),
));
}
if let Some(known_zero) = match k {
1 => Some(-1.173_713_222_709_128),
2 => Some(-3.271_093_302_836_353),
3 => Some(-4.830_737_841_662_016),
4 => Some(-6.169_852_128_312_894),
5 => Some(-7.376_762_079_367_763),
_ => None,
} {
return Ok(F::from_f64(known_zero).expect("Operation failed"));
}
let k_f = F::from_usize(k).expect("Operation failed");
let pi = F::from_f64(std::f64::consts::PI).expect("Operation failed");
let three_fourths = F::from_f64(0.75).expect("Operation failed");
let s = (three_fourths * (k_f + F::from_f64(0.25).expect("Operation failed")) * pi)
.powf(F::from_f64(2.0 / 3.0).expect("Operation failed"));
let initial_guess = -s;
let mut zero = initial_guess;
for _ in 0..20 {
let f_val = bi(zero);
let fp_val = bip(zero);
if fp_val.abs() < F::epsilon() {
break;
}
let correction = f_val / fp_val;
zero = zero - correction;
if correction.abs() < F::from_f64(1e-12).expect("Operation failed") {
break;
}
}
if zero > F::zero() {
return Err(SpecialError::ValueError(
"bi_zeros: failed to converge to negative zero".to_string(),
));
}
Ok(zero)
}
#[allow(dead_code)]
pub fn itairy<F: Float + FromPrimitive + Debug>(x: F) -> (F, F) {
let n_points = 100;
let h = x / F::from_usize(n_points).expect("Operation failed");
let mut integral_ai = F::zero();
let mut integral_bi = F::zero();
for i in 0..=n_points {
let t = F::from_usize(i).expect("Operation failed") * h;
let weight = if i == 0 || i == n_points {
F::one()
} else if i % 2 == 1 {
F::from_f64(4.0).expect("Operation failed")
} else {
F::from_f64(2.0).expect("Operation failed")
};
integral_ai = integral_ai + weight * ai(t);
integral_bi = integral_bi + weight * bi(t);
}
integral_ai = integral_ai * h / F::from_f64(3.0).expect("Operation failed");
integral_bi = integral_bi * h / F::from_f64(3.0).expect("Operation failed");
(integral_ai, integral_bi)
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_ai() {
assert_relative_eq!(ai(0.0), 0.3550280538878172, epsilon = 1e-10);
assert_relative_eq!(ai(1.0), 0.1352924163128814, epsilon = 1e-10);
assert_relative_eq!(ai(2.0), 0.03492413042327235, epsilon = 1e-10);
assert_relative_eq!(ai(5.0), 0.0001083277795169, epsilon = 1e-10);
assert_relative_eq!(ai(-1.0), 0.5355608832923521, epsilon = 1e-10);
assert_relative_eq!(ai(-2.0), 0.22740742820168557, epsilon = 1e-10);
assert_relative_eq!(ai(-5.0), 0.3507610090241142, epsilon = 1e-10);
}
#[test]
fn test_aip() {
assert_relative_eq!(aip(0.0), -0.25881940379280678, epsilon = 1e-10);
assert_relative_eq!(aip(1.0), -0.16049975743698353, epsilon = 1e-10);
assert_relative_eq!(aip(2.0), -0.06120049354097896, epsilon = 1e-10);
assert_relative_eq!(aip(5.0), -0.0003280924942020832, epsilon = 1e-10);
assert_relative_eq!(aip(-1.0), -0.3271928185544436, epsilon = 1e-10);
assert_relative_eq!(aip(-2.0), 0.18836677954676762, epsilon = 1e-10);
assert_relative_eq!(aip(-5.0), 0.7845177219792484, epsilon = 1e-10);
}
#[test]
fn test_bi() {
assert_relative_eq!(bi(0.0), 0.6149266274460007, epsilon = 1e-10);
assert_relative_eq!(bi(1.0), 1.2074235949528715, epsilon = 1e-10);
assert_relative_eq!(bi(2.0), 3.5424680997112654, epsilon = 1e-10);
assert_relative_eq!(bi(5.0), 83.73823961011828, epsilon = 1e-8);
assert_relative_eq!(bi(-1.0), 0.103_997_389_496_944_6, epsilon = 1e-10);
assert_relative_eq!(bi(-2.0), 0.37339167942543735, epsilon = 1e-10);
assert_relative_eq!(bi(-5.0), 0.3757289802157, epsilon = 1e-10);
}
#[test]
fn test_bip() {
assert_relative_eq!(bip(0.0), 0.4482883573538264, epsilon = 1e-10);
assert_relative_eq!(bip(1.0), 1.0434774887138, epsilon = 1e-10);
assert_relative_eq!(bip(2.0), 3.3662351522409107, epsilon = 1e-10);
assert_relative_eq!(bip(5.0), 148.34022202713066, epsilon = 1e-8);
assert_relative_eq!(bip(-1.0), 0.5383830805628176, epsilon = 1e-10);
assert_relative_eq!(bip(-2.0), -0.13289576834890213, epsilon = 1e-10);
assert_relative_eq!(bip(-5.0), -0.7771388142155, epsilon = 1e-10);
}
}