//! 二次插值函数。 //! //! 重构自 TLUSTY `yint.f` /// 二次插值。 /// /// 给定三个点 (xl[0],yl[0]), (xl[1],yl[1]), (xl[2],yl[2]), /// 计算 xl0 处的插值结果。 /// /// # 参数 /// * `xl` - x 坐标数组(长度为 3) /// * `yl` - y 坐标数组(长度为 3) /// * `xl0` - 需要插值的位置 /// /// # 返回值 /// 返回插值结果 /// /// # 注意 /// 调用者需确保 xl[0], xl[1], xl[2] 互不相等 pub fn yint(xl: &[f64], yl: &[f64], xl0: f64) -> f64 { // Fortran 索引转换:XL(1) -> xl[0], XL(2) -> xl[1], XL(3) -> xl[2] let a0 = (xl[1] - xl[0]) * (xl[2] - xl[1]) * (xl[2] - xl[0]); let a1 = (xl0 - xl[1]) * (xl0 - xl[2]) * (xl[2] - xl[1]); let a2 = (xl0 - xl[0]) * (xl[2] - xl0) * (xl[2] - xl[0]); let a3 = (xl0 - xl[0]) * (xl0 - xl[1]) * (xl[1] - xl[0]); (yl[0] * a1 + yl[1] * a2 + yl[2] * a3) / a0 } #[cfg(test)] mod tests { use super::*; use approx::assert_relative_eq; #[test] fn test_yint_at_points() { let xl = [0.0, 1.0, 2.0]; let yl = [1.0, 2.0, 5.0]; // 测试在插值节点上的值 assert_relative_eq!(yint(&xl, &yl, 0.0), 1.0, epsilon = 1e-15); assert_relative_eq!(yint(&xl, &yl, 1.0), 2.0, epsilon = 1e-15); assert_relative_eq!(yint(&xl, &yl, 2.0), 5.0, epsilon = 1e-15); } #[test] fn test_yint_quadratic() { // y = x^2 let xl = [0.0, 1.0, 2.0]; let yl = [0.0, 1.0, 4.0]; assert_relative_eq!(yint(&xl, &yl, 0.5), 0.25, epsilon = 1e-15); assert_relative_eq!(yint(&xl, &yl, 1.5), 2.25, epsilon = 1e-15); } #[test] fn test_yint_extrapolation() { let xl = [0.0, 1.0, 2.0]; let yl = [0.0, 1.0, 4.0]; // 外推: y = x^2 assert_relative_eq!(yint(&xl, &yl, -1.0), 1.0, epsilon = 1e-15); assert_relative_eq!(yint(&xl, &yl, 3.0), 9.0, epsilon = 1e-15); } #[test] fn test_yint_vs_lagran() { // yint 和 lagran 应该给出相同的结果 use crate::tlusty::math::lagran; let xl = [0.0, 1.0, 2.0]; let yl = [1.0, 3.0, 2.0]; for x in [0.0, 0.5, 1.0, 1.5, 2.0, 3.0].iter() { let y1 = yint(&xl, &yl, *x); let y2 = lagran(xl[0], xl[1], xl[2], yl[0], yl[1], yl[2], *x); assert_relative_eq!(y1, y2, epsilon = 1e-15); } } }