competitive_library/other/
ternary_search.rs

1pub fn ternary_search(mut low: f64, mut high: f64, f: Box<dyn Fn(f64) -> f64>) -> f64 {
2    let mut cnt = 1000;
3    while cnt > 0 {
4        let c1 = (low * 2.0 + high) / 3.0;
5        let c2 = (low + high * 2.0) / 3.0;
6
7        if f(c1) > f(c2) {
8            low = c1;
9        } else {
10            high = c2;
11        }
12        cnt -= 1;
13    }
14    high
15}
16
17#[cfg(test)]
18mod tests {
19    use super::ternary_search;
20    // https://atcoder.jp/contests/abc279/tasks/abc279_d
21    #[test]
22    fn a() {
23        let (a, b) = (10.0, 1.0);
24        let f = move |x: f64| (x * b) + a / (x + 1.0).sqrt();
25        let h = ternary_search(0.0, 1_000_000_000_000_000_000.0, Box::new(f));
26
27        assert!((f((h + 0.5) as i64 as f64) - 7.773_502_691_9).abs() < 0.000_001);
28    }
29    #[test]
30    fn b() {
31        let (a, b) = (5.0, 10.0);
32        let f = move |x: f64| (x * b) + a / (x + 1.0).sqrt();
33        let h = ternary_search(0.0, 1_000_000_000_000_000_000.0, Box::new(f));
34
35        assert!(dbg!((f((h + 0.5) as i64 as f64) - 5.000_000_000_0).abs()) < 0.000_001);
36    }
37
38    #[test]
39    fn c() {
40        let (a, b) = (1_000_000_000_000_000_000.0, 100.0);
41        let f = move |x: f64| (x * b) + a / (x + 1.0).sqrt();
42        let h = ternary_search(0.0, 1_000_000_000_000_000_000.0, Box::new(f));
43
44        assert!(dbg!((f((h + 0.4) as i64 as f64) - 8_772_053_214_538.598_f64).abs()) < 0.01);
45    }
46}