//! 通用插值过程 //! //! 原始 Fortran: interp.f //! 支持 (NPOL-1) 阶插值,可选对数插值 use crate::state::MDEPTH; /// 通用插值过程 /// /// 对给定点进行 (NPOL-1) 阶拉格朗日插值 /// /// # 参数 /// - `x`: 原始 x 坐标数组 (可能被修改) /// - `y`: 原始 y 值数组 (可能被修改) /// - `xx`: 新 x 坐标数组 (可能被修改) /// - `yy`: 输出的插值结果 /// - `nx`: 原始数组大小 /// - `nxx`: 新数组大小 /// - `npol`: 插值阶数+1 /// - `ilogx`: 1 表示对 x 取对数插值 /// - `ilogy`: 1 表示对 y 取对数插值 /// /// # 说明 /// - 当 NPOL <= 0 或 NX <= 0 时,直接复制数据 /// - 对数插值会修改输入数组 pub fn interp( x: &mut [f64], y: &mut [f64], xx: &mut [f64], yy: &mut [f64], nx: usize, nxx: usize, npol: i32, ilogx: i32, ilogy: i32, ) { // 常量 const LN10: f64 = 2.30258509299405; // 无效情况: 直接复制 if npol <= 0 || nx == 0 { let n = if nxx >= nx { nxx } else { nx }; for i in 0..n.min(MDEPTH) { if i < xx.len() && i < x.len() { xx[i] = x[i]; } if i < yy.len() && i < y.len() { yy[i] = y[i]; } } return; } // 对数插值预处理 if ilogx > 0 { for i in 0..nx.min(x.len()) { x[i] = x[i].ln() / LN10; // log10 } for i in 0..nxx.min(xx.len()) { xx[i] = xx[i].ln() / LN10; // log10 } } if ilogy > 0 { for i in 0..nx.min(y.len()) { y[i] = y[i].ln() / LN10; // log10 } } // 插值参数 let nm = (npol + 1) as usize / 2; let nm1 = nm + 1; let nup = nx + nm1 - npol as usize; // 对每个目标点进行插值 for id in 0..nxx { let xxx = xx[id]; // 找到插值区间 let mut i = nm1; while i <= nup && xxx > x[i - 1] { i += 1; } if i > nup { i = nup; } let j = i - nm; let jj = j + npol as usize - 1; // 拉格朗日插值 let mut yyy = 0.0; for k in j..=jj { let mut t = 1.0; for m in j..=jj { if k != m { t *= (xxx - x[m - 1]) / (x[k - 1] - x[m - 1]); } } yyy += y[k - 1] * t; } yy[id] = yyy; } // 对数插值后处理: 恢复原值 if ilogx > 0 { for i in 0..nx.min(x.len()) { x[i] = (x[i] * LN10).exp(); } for i in 0..nxx.min(xx.len()) { xx[i] = (xx[i] * LN10).exp(); } } if ilogy > 0 { for i in 0..nx.min(y.len()) { y[i] = (y[i] * LN10).exp(); } for i in 0..nxx.min(yy.len()) { yy[i] = (yy[i] * LN10).exp(); } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_interp_linear() { // 线性函数 y = 2x let mut x = vec![1.0, 2.0, 3.0, 4.0, 5.0]; let mut y = vec![2.0, 4.0, 6.0, 8.0, 10.0]; let mut xx = vec![1.5, 2.5, 3.5, 4.5]; let mut yy = vec![0.0; 4]; interp( &mut x, &mut y, &mut xx, &mut yy, 5, 4, 2, 0, 0 // npol=2 (线性), 无对数 ); assert!((yy[0] - 3.0).abs() < 1e-10); assert!((yy[1] - 5.0).abs() < 1e-10); assert!((yy[2] - 7.0).abs() < 1e-10); assert!((yy[3] - 9.0).abs() < 1e-10); } #[test] fn test_interp_quadratic() { // 二次函数 y = x^2 let mut x = vec![1.0, 2.0, 3.0, 4.0, 5.0]; let mut y = vec![1.0, 4.0, 9.0, 16.0, 25.0]; let mut xx = vec![2.5]; let mut yy = vec![0.0]; interp( &mut x, &mut y, &mut xx, &mut yy, 5, 1, 3, 0, 0 // npol=3 (二次) ); // 2.5^2 = 6.25 assert!((yy[0] - 6.25).abs() < 1e-10); } #[test] fn test_interp_log() { // 对数插值测试 let mut x = vec![1.0, 10.0, 100.0, 1000.0]; let mut y = vec![1.0, 2.0, 3.0, 4.0]; let mut xx = vec![10.0_f64.sqrt()]; // sqrt(10) let mut yy = vec![0.0]; interp( &mut x, &mut y, &mut xx, &mut yy, 4, 1, 2, 1, 0 // 对数 x ); // 在 log10 空间中,sqrt(10) ≈ 0.5,应该得到 1.5 assert!((yy[0] - 1.5).abs() < 1e-10); } }