1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
//! Stern--Brocot tree
/// Stern--Brocot tree
///
/// $a/b = 0/1=0$ と $c/d = 1/0=\\infty$ で初期化し、その mediant
/// $x/y = (a+b)/(c+d)$
/// を探索する。
///
/// $x/y$ が所望の条件 `ok` を満たすならそれを [`Ok`] として返す。
/// 条件 `large` を満たすなら $c/d\\gets x/y$、そうでなければ $a/b\\gets x/y$
/// として探索を進める。
/// 分母が $n$ を超えても `ok` を満たさなければ、$((a, b), (c, d))$ を
/// [`Err`] として返す。
///
/// [`Ok`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Ok
/// [`Err`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Err
///
/// # Examples
/// ```
/// use nekolib::math::stern_brocot;
///
/// let (num, den) =
/// stern_brocot(10_i128.pow(18), |n, d| n * n > 3 * d * d, |_, _| false)
/// .err().unwrap().0;
///
/// let sqrt3 = num as f64 / den as f64;
/// assert!((sqrt3 - 3.0_f64.sqrt()).abs() < 1.0e-16);
/// assert_eq!((num, den), (734231055024833855, 423908497265970753));
/// ```
pub fn stern_brocot(
n: i128,
mut large: impl FnMut(i128, i128) -> bool,
mut ok: impl FnMut(i128, i128) -> bool,
) -> Result<(i128, i128), ((i128, i128), (i128, i128))> {
let (mut a, mut b) = (0, 1);
let (mut c, mut d) = (1, 0);
loop {
let x = a + c;
let y = b + d;
if y > n {
return Err(((a, b), (c, d)));
}
if ok(x, y) {
return Ok((x, y));
}
if large(x, y) {
c = x;
d = y;
} else {
a = x;
b = y;
}
}
}