//! 与 Fortran 参考实现对比的集成测试 //! //! 这些测试确保 Rust 实现与原始 Fortran 代码输出一致。 use tlusty_rust::tlusty::math::{eint, erfcin, erfcx, expo, ffcros, gntk, lagran, raph, sghe12, tridag, yint, ylintp}; use approx::assert_relative_eq; /// 测试 expo 函数与 Fortran 对比 #[test] fn test_expo_vs_fortran() { // Fortran 参考值 (x, y) 对 let ref_values = [ (-80.0, 1.8048513878454153E-35), (-60.0, 8.7565107626965200E-27), (-40.0, 4.2483542552915889E-18), (-20.0, 2.0611536224385579E-09), (0.0, 1.0), (20.0, 4.8516519540979028E+08), (40.0, 2.3538526683702000E+17), (60.0, 1.1420073898156842E+26), (80.0, 5.5406223843935098E+34), ]; for (x, expected) in ref_values { let result = expo(x); assert_relative_eq!(result, expected, epsilon = 1e-10); } } /// 测试 yint 函数与 Fortran 对比 #[test] fn test_yint_vs_fortran() { let xl = [0.0, 1.0, 2.0]; let yl = [0.0, 1.0, 4.0]; // f(x) = x^2 // Fortran 参考值 (x0, y) 对 let ref_values = [ (-0.5, 2.5000000000000000E-01), (0.0, 0.0), (0.5, 2.5000000000000000E-01), (1.0, 1.0), (1.5, 2.2500000000000000E+00), (2.0, 4.0), (2.5, 6.2500000000000000E+00), (3.0, 9.0), ]; for (x0, expected) in ref_values { let result = yint(&xl, &yl, x0); assert_relative_eq!(result, expected, epsilon = 1e-10); } } /// 测试 lagran 函数与 Fortran 对比 #[test] fn test_lagran_vs_fortran() { // Fortran 参考值 (x, y) 对 let ref_values = [ (-0.5, 2.5000000000000000E-01), (0.0, 0.0), (0.5, 2.5000000000000000E-01), (1.0, 1.0), (1.5, 2.2500000000000000E+00), (2.0, 4.0), (2.5, 6.2500000000000000E+00), (3.0, 9.0), ]; for (x, expected) in ref_values { let result = lagran(0.0, 1.0, 2.0, 0.0, 1.0, 4.0, x); assert_relative_eq!(result, expected, epsilon = 1e-10); } } /// 测试 eint 函数与 Fortran 对比 /// /// 注意: eint 使用 Abramowitz-Stegun 多项式近似,本身有约 1e-8 的误差 #[test] fn test_eint_vs_fortran() { // Fortran 参考值 (t, e1, e2, e3) let ref_values = [ (0.5, 5.5977351132042752E-01, 3.2664390405241966E-01, 2.2160435384321181E-01), (1.0, 2.1938394266180694E-01, 1.4849549850963539E-01, 1.0969197133090347E-01), (1.5, 1.0001958508512092E-01, 7.3100782520748447E-02, 5.6739493183653573E-02), (2.0, 4.8900511239767130E-02, 3.7534260757078441E-02, 3.0133380861227910E-02), (2.5, 2.4914918849736040E-02, 1.9797701499558701E-02, 1.6295372437501024E-02), (3.0, 1.3048381677757128E-02, 1.0641923334592560E-02, 8.9306491820431329E-03), (3.5, 6.9701400793792615E-03, 5.8018931444910847E-03, 4.9453787082998531E-03), (4.0, 3.7793524728216067E-03, 3.1982289974477520E-03, 2.7613614494715853E-03), (4.5, 2.0734007690333418E-03, 1.7786930775922690E-03, 1.5524388445385473E-03), (5.0, 1.1482955955412033E-03, 9.9646902137945012E-04, 8.7780094609410820E-04), ]; for (t, exp_e1, exp_e2, exp_e3) in ref_values { let (e1, e2, e3) = eint(t); // 多项式近似本身有约 1e-7 的误差 assert_relative_eq!(e1, exp_e1, epsilon = 1e-7); assert_relative_eq!(e2, exp_e2, epsilon = 1e-7); assert_relative_eq!(e3, exp_e3, epsilon = 1e-7); } } /// 测试 tridag 函数与 Fortran 对比 #[test] fn test_tridag_vs_fortran() { let a = [0.0, 1.0, 1.0]; let b = [2.0, 2.0, 2.0]; let c = [1.0, 1.0, 0.0]; let r = [5.0, 6.0, 5.0]; // Fortran 参考值 let expected = [1.9999999999999998E+00, 1.0000000000000004E+00, 1.9999999999999998E+00]; let u = tridag(&a, &b, &c, &r); for i in 0..3 { assert_relative_eq!(u[i], expected[i], epsilon = 1e-10); } } /// 测试 gntk 函数与 Fortran 对比 /// /// 注意: gntk 仅在特定频率范围内有效,低频时值异常大 #[test] fn test_gntk_vs_fortran() { // Fortran 参考值 (fr, g1, g2, g3, g4) // 注意: 低频时值异常大,这是原 Fortran 代码的行为 let ref_values: [(f64, f64, f64, f64, f64); 5] = [ // (fr, g1, g2, g3, g4) (1.0, -2.2684599999999999E+30, 4.0767699999999764E+28, 1.0353999999999900E+28, 1.0), (1.5, -1.0082044444444443E+30, 1.8118977777777619E+28, 4.6017777777777113E+27, 1.0), (2.0, -5.6711499999999998E+29, 1.0191924999999882E+28, 2.5884999999999503E+27, 1.0), (2.5, -3.6295360000000007E+29, 6.5228319999999065E+27, 1.6566399999999606E+27, 1.0), (3.0, -2.5205111111111108E+29, 4.5297444444443653E+27, 1.1504444444444115E+27, 1.0), ]; for (fr, exp_g1, exp_g2, exp_g3, exp_g4) in ref_values { assert_relative_eq!(gntk(1, fr), exp_g1, epsilon = 1e-5); assert_relative_eq!(gntk(2, fr), exp_g2, epsilon = 1e-5); assert_relative_eq!(gntk(3, fr), exp_g3, epsilon = 1e-5); assert_relative_eq!(gntk(4, fr), exp_g4, epsilon = 1e-10); } } /// 测试 raph 函数与 Fortran 对比 #[test] fn test_raph_vs_fortran() { // Fortran 参考值 let gam = 1.0; let z1 = 0.5; let z2 = 0.3; let a1 = 1.0; let a2 = 2.0; let expected_dgam = 1.1134502923976604E+00; let result = raph(gam, z1, z2, a1, a2); assert_relative_eq!(result, expected_dgam, epsilon = 1e-10); } /// 测试 ffcros 函数与 Fortran 对比 #[test] fn test_ffcros_vs_fortran() { // Fortran 参考值 - 都返回 0 assert_relative_eq!(ffcros(1, 1, 5000.0, 1e15), 0.0, epsilon = 1e-10); assert_relative_eq!(ffcros(0, 1, 5000.0, 1e15), 0.0, epsilon = 1e-10); assert_relative_eq!(ffcros(1, 0, 5000.0, 1e15), 0.0, epsilon = 1e-10); } /// 测试 erfcx 函数与 Fortran 对比 #[test] fn test_erfcx_vs_fortran() { // Fortran 参考值 (x, erfc(x)) let ref_values = [ (0.0, 9.9999999900000003E-01), (1.0, 1.5729931025241004E-01), (2.0, 4.6778604187811181E-03), (3.0, 2.2105148897756218E-05), (4.0, 1.5460295789338392E-08), (5.0, 1.5478170433336780E-12), ]; for (x, expected) in ref_values { let result = erfcx(x); assert_relative_eq!(result, expected, epsilon = 1e-10); } } /// 测试 erfcin 函数与 Fortran 对比 #[test] fn test_erfcin_vs_fortran() { // Fortran 参考值 (x, inverfc(x)) let ref_values = [ (0.1, 1.1630870584411228E+00), (0.2, 9.0619407882011216E-01), (0.3, 7.3286914940754166E-01), (0.4, 5.9511595740386936E-01), (0.5, 4.7693612816435027E-01), (0.6, 3.7080712947986716E-01), (0.7, 2.7246281969225733E-01), (0.8, 1.7914355790849454E-01), (0.9, 8.8855922153797298E-02), ]; for (x, expected) in ref_values { let result = erfcin(x); // 迭代方法精度约 1e-5 assert_relative_eq!(result, expected, epsilon = 1e-4); } } /// 测试 sghe12 函数与 Fortran 对比 #[test] fn test_sghe12_vs_fortran() { // Fortran 参考值 (fr, sghe12) let ref_values = [ (1.0e15, 9.4707561349546987E-18), (2.0e15, 1.5053055952018010E-18), (3.0e15, 5.5703180206730121E-19), (4.0e15, 2.8323006047161224E-19), (5.0e15, 1.6942830613190454E-19), ]; for (fr, expected) in ref_values { let result = sghe12(fr); assert_relative_eq!(result, expected, epsilon = 1e-10); } } /// 测试 ylintp 函数与 Fortran 对比 #[test] fn test_ylintp_vs_fortran() { // f(x) = 2x + 1 let x = [0.0, 1.0, 2.0, 3.0]; let y = [1.0, 3.0, 5.0, 7.0]; // Fortran 参考值 (xint, y) let ref_values = [ (-0.5, 0.0), // 外推 (0.0, 1.0), (0.5, 2.0), (1.0, 3.0), (1.5, 4.0), (2.0, 5.0), (2.5, 6.0), (3.0, 7.0), (3.5, 8.0), // 外推 (4.0, 9.0), // 外推 ]; for (xint, expected) in ref_values { let result = ylintp(&x, &y, xint); assert_relative_eq!(result, expected, epsilon = 1e-10); } }