SpectraRust/src/tlusty/math/interpolation/yint.rs
2026-03-27 11:59:23 +08:00

81 lines
2.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 二次插值函数。
//!
//! 重构自 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);
}
}
}