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
64
65
66
67
68
69
70
71
72
73
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);
        }
    }
}