use num_bigint::{BigUint};
use num_traits::{Zero, One};
use std::ops::{Add, Mul, Div};
use num_bigint::ToBigUint;
pub struct BigCollatz {
curr: BigUint,
done: bool,
pub start: BigUint,
pub steps: u32,
}
pub struct CollatzStep {
pub step: u32,
pub curr: BigUint,
}
impl BigCollatz {
pub fn new(ini: BigUint) -> BigCollatz {
BigCollatz {
start: ini.clone(),
curr: ini.clone(),
steps: 0,
done: false,
}
}
}
impl Iterator for BigCollatz {
type Item = CollatzStep;
fn next(&mut self) -> Option<CollatzStep> {
if self.done { return None; };
let one: BigUint = BigUint::one();
let zero: BigUint = BigUint::zero();
let two: BigUint = BigUint::from(2u32);
let three: BigUint = BigUint::from(3u32);
let curr = &self.curr;
let result = curr.clone();
if curr % &two == zero {
self.curr = curr.div(&two);
} else {
self.curr = curr.mul(&three).add(&one);
}
if self.curr <= one {
self.done = true
}
self.steps += 1;
Some(CollatzStep {
step: self.steps,
curr: result,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let c = BigCollatz::new(100.to_biguint().unwrap());
for x in c {
println!("n:{}, step:{}", x.curr, x.step);
assert_eq!(x.curr > BigUint::one(), true);
}
}
}