1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
use crate::ubig::UBig;
use alloc::vec;
use dashu_base::{DivRem, PowerOfTwo};
impl UBig {
/// Divide out all multiples of the factor from the integer,
/// returns the exponent of the removed factor.
///
/// For self = 0 or factor = 0 or 1, this method returns None.
pub fn remove(&mut self, factor: &UBig) -> Option<usize> {
if self.is_zero() || factor.is_zero() || factor.is_one() {
return None;
}
// shortcut for power of 2
if factor.is_power_of_two() {
let bits = factor.trailing_zeros().unwrap();
let exp = self.trailing_zeros().unwrap() / bits;
*self >>= exp * bits;
return Some(exp);
}
let (mut q, r) = (&*self).div_rem(factor);
if !r.is_zero() {
return Some(0);
}
// first stage, division with exponentially growing factors
let mut exp = 1;
let mut pows = vec![factor.sqr()];
loop {
let last = pows.last().unwrap();
let (new_q, r) = (&q).div_rem(last);
if !r.is_zero() {
break;
}
exp += 1 << pows.len();
q = new_q;
let next_sq = last.sqr();
pows.push(next_sq);
}
// second stage, division from highest power to the lowest
while let Some(last) = pows.pop() {
let (new_q, r) = (&q).div_rem(last);
if r.is_zero() {
exp += 1 << (pows.len() + 1);
q = new_q;
}
}
// last division
let (new_q, r) = (&q).div_rem(factor);
if r.is_zero() {
exp += 1;
q = new_q;
}
*self = q;
Some(exp)
}
}