pub fn integrate<F>(f: F, a: f64, b: f64) -> f64
where
F: Fn(f64) -> f64,
{
let c = 0.5 * (b - a);
let d = 0.5 * (a + b);
c * tanhsinh(|t| {
let out = f(c * t + d);
if out.is_finite() {
out
} else {
0.0
}
})
}
fn tanhsinh<F>(f: F) -> f64
where
F: Fn(f64) -> f64,
{
let mut integral = 0.0;
for i in 0..100 {
integral += WEIGHTS[i] * f(ABSCISSAE[i]);
}
integral
}
pub const ABSCISSAE: [f64; 100] = [
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-1.0,
-0.999_999_999_999_999_999_999_999_92,
-0.999_999_999_999_999_999_999_999_95,
-0.999_999_999_999_999_999_999_999_98,
-0.999_999_999_999_999_999_999_999_91,
-0.999_999_999_999_999_999_999_999_95,
-0.999_999_999_999_999_999_999_998_77,
-0.999_999_999_999_999_999_999_103_26,
-0.999_999_999_999_999_999_703_932_4,
-0.999_999_999_999_999_950_531_716_2,
-0.999_999_999_999_995_4,
-0.999_999_999_999_755_4,
-0.999_999_999_991_728_4,
-0.999_999_999_814_670_3,
-0.999_999_997_111_343_6,
-0.999_999_967_297_845_9,
-0.999_999_720_654_543_6,
-0.999_998_137_805_321,
-0.999_990_019_143_856_7,
-0.999_955_840_978_693_4,
-0.999_834_913_162_265,
-0.999_467_635_803_999,
-0.998_491_938_731_602_9,
-0.996_186_771_585_243_7,
-0.991_272_560_236_550_9,
-0.981_701_565_973_876_9,
-0.964_495_379_931_111_4,
-0.935_708_688_740_139_8,
-0.890_613_153_970_636_9,
-0.824_190_972_468_412_2,
-0.731_982_954_977_568_5,
-0.611_228_933_047_550_6,
-0.462_072_342_445_637_1,
-0.288_435_163_890_398_6,
-0.098_120_697_049_078_77,
0.098_120_697_049_078_75,
0.288_435_163_890_398_64,
0.462_072_342_445_637_19,
0.611_228_933_047_550_7,
0.731_982_954_977_568_5,
0.824_190_972_468_412_2,
0.890_613_153_970_636_9,
0.935_708_688_740_139_9,
0.964_495_379_931_111_5,
0.981_701_565_973_876_9,
0.991_272_560_236_551,
0.996_186_771_585_243_7,
0.998_491_938_731_603,
0.999_467_635_803_999,
0.999_834_913_162_265,
0.999_955_840_978_693_5,
0.999_990_019_143_856_8,
0.999_998_137_805_321_1,
0.999_999_720_654_543_7,
0.999_999_967_297_846,
0.999_999_997_111_343_7,
0.999_999_999_814_670_2,
0.999_999_999_991_728_4,
0.999_999_999_999_755_4,
0.999_999_999_999_995_4,
0.999_999_999_999_999_950_531_74,
0.999_999_999_999_999_999_703_94,
0.999_999_999_999_999_999_999_156,
0.999_999_999_999_999_999_999_987,
0.999_999_999_999_999_999_999_985,
0.999_999_999_999_999_999_999_951,
0.999_999_999_999_999_999_999_958,
0.999_999_999_999_999_999_999_955,
0.999_999_999_999_999_999_999_912,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
];
pub const WEIGHTS: [f64; 100] = [
0.0,
4.575_617_930_178_338e-295,
3.316_994_462_570_346e-260,
1.865_212_622_495_173_5e-229,
2.479_121_672_052_092e-202,
2.081_537_448_295_626e-178,
2.628_202_011_356_882_4e-157,
1.072_629_885_654_983_3e-138,
2.779_482_305_261_637e-122,
8.296_418_844_663_515e-108,
4.824_667_051_120_648e-95,
8.690_880_649_537_159e-84,
7.300_384_623_604_137e-74,
4.102_662_749_806_205e-65,
2.120_927_715_027_845e-57,
1.335_824_993_406_033_2e-50,
1.313_406_878_320_599_1e-44,
2.508_807_816_395_078_6e-39,
1.129_193_867_059_432_8e-34,
1.419_894_975_881_043_8e-30,
5.796_754_421_896_154_4e-27,
8.772_732_913_927_396e-24,
5.532_447_125_135_289e-21,
1.612_026_230_404_078_1e-18,
2.377_241_245_744_043_6e-16,
1.922_871_877_455_573e-14,
9.158_786_378_811_089e-13,
2.735_019_685_607_782_3e-11,
5.412_036_348_700_474e-10,
7.452_095_495_199_113e-9,
7.455_643_353_281_056e-8,
5.630_935_258_210_419e-7,
3.320_892_221_887_424e-6,
1.575_869_255_697_420_2e-5,
6.178_940_879_197_28e-5,
2.049_612_222_935_924_2e-4,
5.873_088_850_232_362e-4,
0.001_480_856_522_480_776_8,
0.003_339_108_906_155_36,
0.006_827_704_416_155_456,
0.012_809_851_589_261_179,
0.022_262_908_367_071_66,
0.036_106_623_280_003_48,
0.054_935_001_719_810_43,
0.078_672_104_392_875_16,
0.106_225_018_644_775_54,
0.135_274_854_478_869_08,
0.162_387_107_725_986_52,
0.183_570_841_955_285,
0.195_234_233_228_838_65,
0.195_234_233_228_838_65,
0.183_570_841_955_285,
0.162_387_107_725_986_52,
0.135_274_854_478_869_08,
0.106_225_018_644_775_54,
0.078_672_104_392_875_16,
0.054_935_001_719_810_43,
0.036_106_623_280_003_48,
0.022_262_908_367_071_66,
0.012_809_851_589_261_179,
0.006_827_704_416_155_456,
0.003_339_108_906_155_36,
0.001_480_856_522_480_776_8,
5.873_088_850_232_362e-4,
2.049_612_222_935_924_2e-4,
6.178_940_879_197_28e-5,
1.575_869_255_697_420_2e-5,
3.320_892_221_887_424e-6,
5.630_935_258_210_419e-7,
7.455_643_353_281_056e-8,
7.452_095_495_199_113e-9,
5.412_036_348_700_474e-10,
2.735_019_685_607_782_3e-11,
9.158_786_378_811_089e-13,
1.922_871_877_455_573e-14,
2.377_241_245_744_043_6e-16,
1.612_026_230_404_078_1e-18,
5.532_447_125_135_289e-21,
8.772_732_913_927_396e-24,
5.796_754_421_896_154_4e-27,
1.419_894_975_881_043_8e-30,
1.129_193_867_059_432_8e-34,
2.508_807_816_395_078_6e-39,
1.313_406_878_320_599_1e-44,
1.335_824_993_406_033_2e-50,
2.120_927_715_027_845e-57,
4.102_662_749_806_205e-65,
7.300_384_623_604_137e-74,
8.690_880_649_537_159e-84,
4.824_667_051_120_648e-95,
8.296_418_844_663_515e-108,
2.779_482_305_261_637e-122,
1.072_629_885_654_983_3e-138,
2.628_202_011_356_882_4e-157,
2.081_537_448_295_626e-178,
2.479_121_672_052_092e-202,
1.865_212_622_495_173_5e-229,
3.316_994_462_570_346e-260,
4.575_617_930_178_338e-295,
0.0,
];
#[cfg(test)]
mod tests_integration {
use super::*;
use RustQuant_utils::{assert_approx_equal, RUSTQUANT_EPSILON as EPS};
#[test]
fn test_quadrature() {
fn f(x: f64) -> f64 {
(x.sin()).exp()
}
let integral = integrate(f, 0.0, 5.0);
assert_approx_equal!(integral, 7.189_119_252_343_784, EPS);
}
}