use crate::Rational;
use crate::conversion::continued_fraction::to_continued_fraction::RationalContinuedFraction;
use crate::conversion::traits::ContinuedFraction;
use crate::conversion::traits::Convergents;
use core::mem::swap;
use malachite_base::num::arithmetic::traits::{AddMulAssign, UnsignedAbs};
use malachite_base::num::basic::traits::{One, Zero};
use malachite_nz::integer::Integer;
use malachite_nz::natural::Natural;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RationalConvergents {
first: bool,
previous_numerator: Integer,
previous_denominator: Natural,
numerator: Integer,
denominator: Natural,
cf: RationalContinuedFraction,
}
impl Iterator for RationalConvergents {
type Item = Rational;
fn next(&mut self) -> Option<Rational> {
if self.first {
self.first = false;
Some(Rational::from(&self.numerator))
} else if let Some(n) = self.cf.next() {
self.previous_numerator
.add_mul_assign(&self.numerator, Integer::from(&n));
self.previous_denominator
.add_mul_assign(&self.denominator, n);
swap(&mut self.numerator, &mut self.previous_numerator);
swap(&mut self.denominator, &mut self.previous_denominator);
Some(Rational {
sign: self.numerator >= 0,
numerator: (&self.numerator).unsigned_abs(),
denominator: self.denominator.clone(),
})
} else {
None
}
}
}
impl Convergents for Rational {
type C = RationalConvergents;
fn convergents(self) -> RationalConvergents {
let (floor, cf) = self.continued_fraction();
RationalConvergents {
first: true,
previous_numerator: Integer::ONE,
previous_denominator: Natural::ZERO,
numerator: floor,
denominator: Natural::ONE,
cf,
}
}
}
impl Convergents for &Rational {
type C = RationalConvergents;
fn convergents(self) -> RationalConvergents {
let (floor, cf) = self.continued_fraction();
RationalConvergents {
first: true,
previous_numerator: Integer::ONE,
previous_denominator: Natural::ZERO,
numerator: floor,
denominator: Natural::ONE,
cf,
}
}
}