nautilus_core/
math.rs
1#[inline]
17#[must_use]
18pub fn linear_weight(x1: f64, x2: f64, x: f64) -> f64 {
19 (x - x1) / (x2 - x1)
20}
21
22#[inline]
23#[must_use]
24pub fn linear_weighting(y1: f64, y2: f64, x1_diff: f64) -> f64 {
25 x1_diff.mul_add(y2 - y1, y1)
26}
27
28#[inline]
29#[must_use]
30pub fn pos_search(x: f64, xs: &[f64]) -> usize {
31 let n_elem = xs.len();
32 let pos = xs.partition_point(|&val| val < x);
33 std::cmp::min(std::cmp::max(pos.saturating_sub(1), 0), n_elem - 1)
34}
35
36#[inline]
37#[must_use]
38pub fn quad_polynomial(x: f64, x0: f64, x1: f64, x2: f64, y0: f64, y1: f64, y2: f64) -> f64 {
39 y0 * (x - x1) * (x - x2) / ((x0 - x1) * (x0 - x2))
40 + y1 * (x - x0) * (x - x2) / ((x1 - x0) * (x1 - x2))
41 + y2 * (x - x0) * (x - x1) / ((x2 - x0) * (x2 - x1))
42}
43
44#[must_use]
45pub fn quadratic_interpolation(x: f64, xs: &[f64], ys: &[f64]) -> f64 {
46 let n_elem = xs.len();
47 let epsilon = 1e-8;
48
49 assert!(
50 (n_elem >= 3),
51 "Need at least 3 points for quadratic interpolation"
52 );
53
54 if x <= xs[0] {
55 return ys[0];
56 }
57
58 if x >= xs[n_elem - 1] {
59 return ys[n_elem - 1];
60 }
61
62 let pos = pos_search(x, xs);
63
64 if (xs[pos] - x).abs() < epsilon {
65 return ys[pos];
66 }
67
68 if pos == 0 {
69 return quad_polynomial(x, xs[0], xs[1], xs[2], ys[0], ys[1], ys[2]);
70 }
71
72 if pos == n_elem - 2 {
73 return quad_polynomial(
74 x,
75 xs[n_elem - 3],
76 xs[n_elem - 2],
77 xs[n_elem - 1],
78 ys[n_elem - 3],
79 ys[n_elem - 2],
80 ys[n_elem - 1],
81 );
82 }
83
84 let w = linear_weight(xs[pos], xs[pos + 1], x);
85
86 linear_weighting(
87 quad_polynomial(
88 x,
89 xs[pos - 1],
90 xs[pos],
91 xs[pos + 1],
92 ys[pos - 1],
93 ys[pos],
94 ys[pos + 1],
95 ),
96 quad_polynomial(
97 x,
98 xs[pos],
99 xs[pos + 1],
100 xs[pos + 2],
101 ys[pos],
102 ys[pos + 1],
103 ys[pos + 2],
104 ),
105 w,
106 )
107}