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}
99#[cfg(test)]
101mod tests {
102 use super::*;
103 #[test]
104 fn test_algorithms() {
105 let x0 = brent_zero(|x: f64| x.sin() - x / 2.0, 1.0, 2.0);
107 let (x1, digits) = (1.8954942796e+00, 10_f64.powi(10));
108 assert_eq!(x1, (x0 * digits).round() / digits);
109 let x0 = brent_zero(|x: f64| 2.0 * x - (-x).exp(), 0.0, 1.0);
110 let (x1, digits) = (3.5173365631e-01, 10_f64.powi(11));
111 assert_eq!(x1, (x0 * digits).round() / digits);
112 let x0 = brent_zero(|x: f64| x * (-x).exp(), -1.0, 0.5);
113 let (x1, digits) = (-4.0352160429e-10, 10_f64.powi(20));
114 assert_eq!(x1, (x0 * digits).round() / digits);
115 let x0 = brent_zero(|x: f64| x.exp() - 1.0 / 100.0 / x / x, 0.0001, 20.0);
116 let (x1, digits) = (9.5344620258e-02, 10_f64.powi(12));
117 assert_eq!(x1, (x0 * digits).round() / digits);
118 let x0 = brent_zero(|x: f64| (x + 3.0) * (x - 1.0) * (x - 1.0), -5.0, 2.0);
119 let (x1, digits) = (-3.0000000000e+00, 10_f64.powi(10));
120 assert_eq!(x1, (x0 * digits).round() / digits);
121 let (df0, digits) = (140.7377356, 10_f64.powi(7)); let df1 = romberg_diff(|x: f64| x.exp() / (x.sin() - x.powi(2)), 1.0);
124 assert_eq!(df0, (df1 * digits).round() / digits);
125 let (df0, digits) = (2.718281828, 10_f64.powi(9));
126 let df1 = romberg_diff(|x: f64| x.exp(), 1.0);
127 assert_eq!(df0, (df1 * digits).round() / digits);
128 let (df0, digits) = (22026.46579, 10_f64.powi(5));
129 let df1 = romberg_diff(|x: f64| x.exp(), 10.0);
130 assert_eq!(df0, (df1 * digits).round() / digits);
131 }
132}