1pub fn brent_zero<F>(mut f: F, a: f64, b: f64) -> f64
5where
6 F: FnMut(f64) -> f64,
7{
8 let macheps = f64::EPSILON.sqrt();
9 let (mut a, mut fa) = (a, f(a));
10 let (mut b, mut fb) = (b, f(b));
11 if (fa * fb) > 0.0 {
12 return f64::NAN;
13 }
14 let (mut c, mut fc) = (a, fa);
15 let (mut d, mut e) = (b - a, b - a);
16 let (mut tol, mut m, mut p, mut q, mut r, mut s);
17 loop {
18 if fc.abs() < fb.abs() {
19 (a, fa) = (b, fb);
20 (b, fb) = (c, fc);
21 (c, fc) = (a, fa);
22 }
23 tol = macheps * (2.0 * b.abs() + 10.0);
24 m = 0.5 * (c - b);
25 if m.abs() <= tol || fb == 0.0 {
26 return b;
27 }
28 if e.abs() < tol || fa.abs() <= fb.abs() {
29 e = m;
30 d = e;
31 } else {
32 s = fb / fa;
33 if a == c {
34 p = 2.0 * m * s;
35 q = 1.0 - s;
36 } else {
37 q = fa / fc;
38 r = fb / fc;
39 p = s * (2.0 * m * q * (q - r) - (b - a) * (r - 1.0));
40 q = (q - 1.0) * (r - 1.0) * (s - 1.0);
41 }
42 if 0.0 < p {
43 q = -q;
44 } else {
45 p = -p;
46 }
47 s = e;
48 e = d;
49 if 2.0 * p < 3.0 * m * q - (tol * q).abs() && p < (0.5 * s * q).abs() {
50 d = p / q;
51 } else {
52 e = m;
53 d = e;
54 }
55 }
56 (a, fa) = (b, fb);
57 b += if tol < d.abs() {
58 d
59 } else if 0.0 < m {
60 tol
61 } else {
62 -tol
63 };
64 fb = f(b);
65 if (0.0 < fb && 0.0 < fc) || (fb.is_sign_negative() && fc.is_sign_negative()) {
66 (c, fc) = (a, fa);
67 e = b - a;
68 d = e;
69 }
70 }
71}
72const N_DIM: usize = 11;
78pub fn romberg_diff<F>(mut f: F, x: f64) -> f64
79where
80 F: FnMut(f64) -> f64,
81{
82 let tol = f64::EPSILON.sqrt() * 2.0;
83 let mut fx: [[f64; N_DIM]; N_DIM] = [[0.0; N_DIM]; N_DIM];
84 let mut h: f64 = if x > 1.0 { 0.01 * x } else { 0.1 * x };
85 fx[0][0] = (f(x + h) - f(x - h)) / 2.0 / h;
86 for i in 1..N_DIM {
87 h /= 2.0;
88 fx[0][i] = (f(x + h) - f(x - h)) / 2.0 / h;
89 for j in 1..i + 1 {
90 fx[j][i] = (fx[j - 1][i] * 4_f64.powi(j as i32) - fx[j - 1][i - 1])
91 / (4_f64.powi(j as i32) - 1.0);
92 }
93 if (fx[i][i] / fx[i - 1][i - 1] - fx[i - 1][i - 1] / fx[i][i]).abs() < tol {
94 return fx[i][i];
95 }
96 }
97 fx[N_DIM - 1][N_DIM - 1]
98}
99pub fn poly1fit(x: &[f64], y: &[f64]) -> (f64, f64) {
124 let (mut sum_xi, mut sum_xixi) = (0.0, 0.0);
125 let (mut sum_yi, mut sum_yixi) = (0.0, 0.0);
126 let num: f64 = (0..usize::min(x.len(), y.len()))
127 .map(|i| {
128 sum_xi += x[i];
129 sum_yi += y[i];
130 sum_xixi += x[i] * x[i];
131 sum_yixi += y[i] * x[i];
132 })
133 .count() as f64;
134 let ci = num * sum_xixi - sum_xi * sum_xi;
135 if ci.abs() > 0.01 {
136 (
137 (sum_yi * sum_xixi - sum_yixi * sum_xi) / ci,
138 (num * sum_yixi - sum_xi * sum_yi) / ci,
139 )
140 } else {
141 let ata = vec![vec![num, sum_xi], vec![sum_xi, sum_xixi]];
142 let atb = vec![sum_yi, sum_yixi];
143 let result = solve_equ(ata, atb);
144 (result[0], result[1])
145 }
146}
147pub fn poly2fit(x: &[f64], y: &[f64]) -> (f64, f64, f64) {
179 let (mut sum_x1, mut sum_x2, mut sum_x3, mut sum_x4) = (0.0, 0.0, 0.0, 0.0);
180 let (mut sum_y1x0, mut sum_y1x1, mut sum_y1x2) = (0.0, 0.0, 0.0);
181 let num: f64 = (0..usize::min(x.len(), y.len()))
182 .map(|i| {
183 let (x1, x2) = (x[i], x[i] * x[i]);
184 sum_x1 += x1;
185 sum_x2 += x2;
186 sum_x3 += x1 * x2;
187 sum_x4 += x2 * x2;
188 sum_y1x0 += y[i];
189 sum_y1x1 += y[i] * x1;
190 sum_y1x2 += y[i] * x2;
191 })
192 .count() as f64;
193 let ci = num * (sum_x2 * sum_x4 - sum_x3 * sum_x3)
194 + sum_x1 * (sum_x3 * sum_x2 - sum_x1 * sum_x4)
195 + sum_x2 * (sum_x1 * sum_x3 - sum_x2 * sum_x2);
196 if ci.abs() > 0.01 {
197 (
198 (sum_y1x0 * (sum_x2 * sum_x4 - sum_x3 * sum_x3)
199 + sum_y1x1 * (sum_x3 * sum_x2 - sum_x1 * sum_x4)
200 + sum_y1x2 * (sum_x1 * sum_x3 - sum_x2 * sum_x2))
201 / ci,
202 (num * (sum_y1x1 * sum_x4 - sum_y1x2 * sum_x3)
203 + sum_x1 * (sum_y1x2 * sum_x2 - sum_y1x0 * sum_x4)
204 + sum_x2 * (sum_y1x0 * sum_x3 - sum_y1x1 * sum_x2))
205 / ci,
206 (num * (sum_x2 * sum_y1x2 - sum_x3 * sum_y1x1)
207 + sum_x1 * (sum_x3 * sum_y1x0 - sum_x1 * sum_y1x2)
208 + sum_x2 * (sum_x1 * sum_y1x1 - sum_x2 * sum_y1x0))
209 / ci,
210 )
211 } else {
212 let ata = vec![
213 vec![num, sum_x1, sum_x2],
214 vec![sum_x1, sum_x2, sum_x3],
215 vec![sum_x2, sum_x3, sum_x4],
216 ];
217 let atb = vec![sum_y1x0, sum_y1x1, sum_y1x2];
218 let result = solve_equ(ata, atb);
219 (result[0], result[1], result[2])
220 }
221}
222fn solve_equ(mut a: Vec<Vec<f64>>, mut b: Vec<f64>) -> Vec<f64> {
224 let n = a.len();
225 let (mut index, mut scale);
226 for k in 0..n {
227 index = k;
228 for i in k + 1..n {
229 if a[i][k] > a[index][k] {
230 index = i;
231 }
232 }
233 if index > k {
234 a.swap(k, index);
235 b.swap(k, index);
236 }
237 for i in k + 1..n {
238 scale = a[i][k] / a[k][k];
239 for j in k..n {
240 a[i][j] -= scale * a[k][j];
241 }
242 b[i] -= scale * b[k];
243 }
244 }
245 let mut x = vec![0.0; b.len()];
246 for k in (0..n).rev() {
247 x[k] = (b[k]
248 - a[k][k + 1..]
249 .iter()
250 .zip(x[k + 1..].iter())
251 .map(|(aj, xj)| aj * xj)
252 .sum::<f64>())
253 / a[k][k];
254 }
255 x
256}
257#[cfg(test)]
259mod tests {
260 use super::*;
261 #[test]
262 fn test_algorithms() {
263 let x0 = brent_zero(|x: f64| x.sin() - x / 2.0, 1.0, 2.0);
265 let (x1, digits) = (1.8954942796e+00, 10_f64.powi(10));
266 assert_eq!(x1, (x0 * digits).round() / digits);
267 let x0 = brent_zero(|x: f64| 2.0 * x - (-x).exp(), 0.0, 1.0);
268 let (x1, digits) = (3.5173365631e-01, 10_f64.powi(11));
269 assert_eq!(x1, (x0 * digits).round() / digits);
270 let x0 = brent_zero(|x: f64| x * (-x).exp(), -1.0, 0.5);
271 let (x1, digits) = (-4.0352160429e-10, 10_f64.powi(20));
272 assert_eq!(x1, (x0 * digits).round() / digits);
273 let x0 = brent_zero(|x: f64| x.exp() - 1.0 / 100.0 / x / x, 0.0001, 20.0);
274 let (x1, digits) = (9.5344620258e-02, 10_f64.powi(12));
275 assert_eq!(x1, (x0 * digits).round() / digits);
276 let x0 = brent_zero(|x: f64| (x + 3.0) * (x - 1.0) * (x - 1.0), -5.0, 2.0);
277 let (x1, digits) = (-3.0000000000e+00, 10_f64.powi(10));
278 assert_eq!(x1, (x0 * digits).round() / digits);
279 let (df0, digits) = (140.7377356, 10_f64.powi(7)); let df1 = romberg_diff(|x: f64| x.exp() / (x.sin() - x.powi(2)), 1.0);
282 assert_eq!(df0, (df1 * digits).round() / digits);
283 let (df0, digits) = (2.718281828, 10_f64.powi(9));
284 let df1 = romberg_diff(|x: f64| x.exp(), 1.0);
285 assert_eq!(df0, (df1 * digits).round() / digits);
286 let (df0, digits) = (22026.46579, 10_f64.powi(5));
287 let df1 = romberg_diff(|x: f64| x.exp(), 10.0);
288 assert_eq!(df0, (df1 * digits).round() / digits);
289 let (c0, c1) = poly1fit(
291 &vec![1.0, 2.0, 3.0, 4.0, 5.0],
292 &vec![4.0, 7.0, 10.0, 13.0, 16.0],
293 );
294 assert_eq!(c0, 1.0);
295 assert_eq!(c1, 3.0);
296 let (c0, c1, c2) = poly2fit(
298 &vec![1.0, 2.0, 3.0, 4.0, 5.0],
299 &vec![9.0, 27.0, 55.0, 93.0, 141.0],
300 );
301 assert_eq!(c0, 1.0);
302 assert_eq!(c1, 3.0);
303 assert_eq!(c2, 5.0);
304 }
305}