//! 插值函数。 //! //! 重构自 TLUSTY `yint.f` 和 `lagran.f` /// 使用 3 点进行二次插值。 /// /// 给定 3 个 x 值和 3 个 y 值的数组,插值求 `xl0` 处的 y 值。 /// /// # 参数 /// /// * `xl` - 3 个 x 坐标的数组 /// * `yl` - 3 个 y 坐标的数组(f(x) 值) /// * `xl0` - 要插值到的 x 值 /// /// # 返回值 /// /// `xl0` 处的插值 y 值。 /// /// # Panics /// /// 如果输入数组不正好有 3 个元素则 panic。 /// /// # 示例 /// /// ``` /// use tlusty_rust::math::yint; /// /// let xl = [0.0, 1.0, 2.0]; /// let yl = [0.0, 1.0, 4.0]; // f(x) = x^2 /// let result = yint(&xl, &yl, 0.5); /// assert!((result - 0.25).abs() < 1e-10); /// ``` pub fn yint(xl: &[f64], yl: &[f64], xl0: f64) -> f64 { assert!(xl.len() == 3 && yl.len() == 3, "yint 需要大小为 3 的数组"); // Fortran 使用 1 索引数组: XL(1), XL(2), XL(3) let x1 = xl[0]; let x2 = xl[1]; let x3 = xl[2]; let y1 = yl[0]; let y2 = yl[1]; let y3 = yl[2]; // A0 = (x2-x1)*(x3-x2)*(x3-x1) let a0 = (x2 - x1) * (x3 - x2) * (x3 - x1); // A1 = (xl0-x2)*(xl0-x3)*(x3-x2) let a1 = (xl0 - x2) * (xl0 - x3) * (x3 - x2); // A2 = (xl0-x1)*(x3-xl0)*(x3-x1) let a2 = (xl0 - x1) * (x3 - xl0) * (x3 - x1); // A3 = (xl0-x1)*(xl0-x2)*(x2-x1) let a3 = (xl0 - x1) * (xl0 - x2) * (x2 - x1); (y1 * a1 + y2 * a2 + y3 * a3) / a0 } /// 三点 Lagrange 插值。 /// /// # 参数 /// /// * `x0`, `x1`, `x2` - 三个点的 x 坐标 /// * `y0`, `y1`, `y2` - 三个点的 y 坐标 /// * `x` - 要插值到的 x 值 /// /// # 返回值 /// /// `x` 处的插值 y 值。 /// /// # 示例 /// /// ``` /// use tlusty_rust::math::lagran; /// /// // 使用点 (0,0), (1,1), (2,4) 插值 f(x) = x^2 /// let result = lagran(0.0, 1.0, 2.0, 0.0, 1.0, 4.0, 0.5); /// assert!((result - 0.25).abs() < 1e-10); /// ``` pub fn lagran(x0: f64, x1: f64, x2: f64, y0: f64, y1: f64, y2: f64, x: f64) -> f64 { // Lagrange 基多项式 let xl0 = (x - x1) * (x - x2) / (x0 - x1) / (x0 - x2); let xl1 = (x - x0) * (x - x2) / (x1 - x0) / (x1 - x2); let xl2 = (x - x0) * (x - x1) / (x2 - x0) / (x2 - x1); y0 * xl0 + y1 * xl1 + y2 * xl2 } #[cfg(test)] mod tests { use super::*; use approx::assert_relative_eq; #[test] fn test_yint_quadratic() { // 测试 f(x) = x^2 let xl = [0.0, 1.0, 2.0]; let yl = [0.0, 1.0, 4.0]; // 中点 let result = yint(&xl, &yl, 0.5); assert_relative_eq!(result, 0.25, epsilon = 1e-10); // 另一点 let result = yint(&xl, &yl, 1.5); assert_relative_eq!(result, 2.25, epsilon = 1e-10); // 已知点(应返回精确值) let result = yint(&xl, &yl, 1.0); assert_relative_eq!(result, 1.0, epsilon = 1e-10); } #[test] fn test_yint_linear() { // 测试 f(x) = 2x + 1 let xl = [0.0, 1.0, 2.0]; let yl = [1.0, 3.0, 5.0]; let result = yint(&xl, &yl, 0.5); assert_relative_eq!(result, 2.0, epsilon = 1e-10); } #[test] fn test_lagran_quadratic() { // 测试 f(x) = x^2 let result = lagran(0.0, 1.0, 2.0, 0.0, 1.0, 4.0, 0.5); assert_relative_eq!(result, 0.25, epsilon = 1e-10); let result = lagran(0.0, 1.0, 2.0, 0.0, 1.0, 4.0, 1.5); assert_relative_eq!(result, 2.25, epsilon = 1e-10); } #[test] fn test_lagran_at_known_points() { // 在已知点应返回精确值 assert_relative_eq!(lagran(0.0, 1.0, 2.0, 0.0, 1.0, 4.0, 0.0), 0.0, epsilon = 1e-10); assert_relative_eq!(lagran(0.0, 1.0, 2.0, 0.0, 1.0, 4.0, 1.0), 1.0, epsilon = 1e-10); assert_relative_eq!(lagran(0.0, 1.0, 2.0, 0.0, 1.0, 4.0, 2.0), 4.0, epsilon = 1e-10); } #[test] fn test_yint_lagran_equivalence() { // yint 和 lagran 对相同数据应给出相同结果 let xl = [1.0, 2.0, 3.0]; let yl = [1.0, 8.0, 27.0]; // f(x) = x^3 let x = 2.5; let yint_result = yint(&xl, &yl, x); let lagran_result = lagran(xl[0], xl[1], xl[2], yl[0], yl[1], yl[2], x); assert_relative_eq!(yint_result, lagran_result, epsilon = 1e-10); } }