use num::rational::Ratio;
use num::Integer;
pub fn limit_denominator<T>(fraction: Ratio<T>, max_denom: T) -> Ratio<T>
where
T: Clone + Integer,
{
if max_denom <= T::one() {
panic!("max_denom must be greater than 1");
}
let mut numer = fraction.numer().clone();
let mut denom = fraction.denom().clone();
if denom <= max_denom {
return fraction;
}
let mut numer_0 = T::zero();
let mut denom_0 = T::one();
let mut numer_1 = T::one();
let mut denom_1 = T::zero();
loop {
let a = numer.div_floor(&denom);
let new_numer = denom_0.clone() + a.clone() * denom_1.clone();
if new_numer > max_denom {
break;
}
let new_denom = numer_0 + a.clone() * numer_1.clone();
numer_0 = numer_1;
denom_0 = denom_1;
numer_1 = new_denom;
denom_1 = new_numer;
let tmp_denom = numer - a * denom.clone();
numer = denom;
denom = tmp_denom;
}
let k = (max_denom - denom_0.clone()).div_floor(&denom_1);
if (T::one() + T::one()) * denom * (denom_0.clone() + k.clone() * denom_1.clone())
<= *fraction.denom()
{
Ratio::new_raw(numer_1, denom_1)
} else {
Ratio::new_raw(numer_0 + k.clone() * numer_1, denom_0 + k * denom_1)
}
}