use rug::{Float, Integer, Rational};
use std::cmp::Ordering;
use super::primitive::float;
fn rational_from_continued_fraction(continued_fraction_form: &[Integer]) -> Rational {
let mut rational = Rational::new();
for (i, integer) in continued_fraction_form.iter().rev().enumerate() {
if i == 0 {
if integer.cmp0() == Ordering::Equal {
continue;
}
rational += Rational::from(Rational::ONE / integer);
} else {
rational = (rational + integer).recip();
}
}
if rational.cmp0() == Ordering::Equal {
rational
} else {
rational.recip()
}
}
pub fn approximate_rational(n: &Float) -> Rational {
let orig = n;
let mut continued_fraction_form = Vec::new();
let mut n = n.clone();
loop {
let (integer, fractional) = n.trunc_fract(float(0));
continued_fraction_form.push(integer.to_integer().unwrap());
let rational = rational_from_continued_fraction(&continued_fraction_form);
let error = float(orig - rational).abs();
if fractional.is_zero() || error < 1e-60 {
break;
}
n = fractional.recip();
}
rational_from_continued_fraction(&continued_fraction_form)
}