use crate::Rational;
use crate::conversion::digits::power_of_2_digits::RationalPowerOf2Digits;
use alloc::vec::Vec;
use malachite_base::num::arithmetic::traits::{Abs, CheckedLogBase2, Floor, UnsignedAbs};
use malachite_base::num::conversion::traits::Digits;
use malachite_nz::natural::Natural;
#[doc(hidden)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RationalGeneralDigits {
base: Rational,
remainder: Rational,
}
impl Iterator for RationalGeneralDigits {
type Item = Natural;
fn next(&mut self) -> Option<Natural> {
if self.remainder == 0u32 {
None
} else {
self.remainder *= &self.base;
let digit = (&self.remainder).floor().unsigned_abs();
self.remainder -= Rational::from(&digit);
Some(digit)
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RationalDigits {
General(RationalGeneralDigits),
PowerOf2(RationalPowerOf2Digits),
}
impl Iterator for RationalDigits {
type Item = Natural;
fn next(&mut self) -> Option<Natural> {
match self {
Self::General(xs) => xs.next(),
Self::PowerOf2(xs) => xs.next(),
}
}
}
impl Rational {
pub fn digits(&self, base: &Natural) -> (Vec<Natural>, RationalDigits) {
if let Some(log_base) = base.checked_log_base_2() {
let (before_point, after_point) = self.power_of_2_digits(log_base);
(before_point, RationalDigits::PowerOf2(after_point))
} else {
let mut remainder = self.abs();
let floor = (&remainder).floor().unsigned_abs();
remainder -= Self::from(&floor);
(
floor.to_digits_asc(base),
RationalDigits::General(RationalGeneralDigits {
base: Self::from(base),
remainder,
}),
)
}
}
}