use crate::Rational;
use crate::conversion::digits::to_power_of_2_digits::to_power_of_2_digits_helper;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use malachite_base::num::arithmetic::traits::{
Abs, AbsAssign, CheckedLogBase2, Floor, UnsignedAbs,
};
use malachite_base::num::conversion::traits::Digits;
use malachite_base::rational_sequences::RationalSequence;
use malachite_nz::natural::Natural;
fn to_digits_helper(x: Rational, base: &Natural) -> (Vec<Natural>, RationalSequence<Natural>) {
if let Some(log_base) = base.checked_log_base_2() {
return to_power_of_2_digits_helper(x, log_base);
}
let floor = (&x).floor();
let mut remainder = x - Rational::from(&floor);
let before_point = floor.unsigned_abs().to_digits_asc(base);
let mut state_map = BTreeMap::new();
let mut digits = Vec::new();
let base = Rational::from(base);
for i in 0.. {
if remainder == 0u32 {
return (before_point, RationalSequence::from_vec(digits));
}
if let Some(previous_i) = state_map.insert(remainder.clone(), i) {
let repeating = digits.drain(previous_i..).collect();
return (before_point, RationalSequence::from_vecs(digits, repeating));
}
remainder *= &base;
let floor = (&remainder).floor().unsigned_abs();
digits.push(floor.clone());
remainder -= Rational::from(floor);
}
unreachable!()
}
impl Rational {
#[inline]
pub fn into_digits(mut self, base: &Natural) -> (Vec<Natural>, RationalSequence<Natural>) {
self.abs_assign();
to_digits_helper(self, base)
}
pub fn to_digits(&self, base: &Natural) -> (Vec<Natural>, RationalSequence<Natural>) {
to_digits_helper(self.abs(), base)
}
}