Skip to content

Commit

Permalink
Moved iterators into src/utils/iterators.
Browse files Browse the repository at this point in the history
  • Loading branch information
tfpf committed Apr 21, 2024
1 parent 2a89de4 commit f77d046
Show file tree
Hide file tree
Showing 13 changed files with 414 additions and 380 deletions.
392 changes: 12 additions & 380 deletions src/utils.rs

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions src/utils/iterators.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pub mod fibonacci;
pub mod polygonal;
pub mod cubes;
pub mod collatz;
pub mod divisors;
pub mod prime_divisors;
pub mod digits;
pub mod bits;
pub mod pythagorean_triplets;
pub mod potential_primes;
pub mod continued_fraction;
24 changes: 24 additions & 0 deletions src/utils/iterators/bits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// Bits iterator. Generates the binary digits of a number from least
/// significant to most significant. Positive numbers only!
pub struct Bits {
num: i64,
}
impl Bits {
pub fn new(num: i64) -> Bits {
Bits { num }
}
}
impl Iterator for Bits {
type Item = i64;
fn next(&mut self) -> Option<i64> {
if self.num == 0 {
None
} else {
let bit = self.num & 1;
self.num >>= 1;
Some(bit)
}
}
}


28 changes: 28 additions & 0 deletions src/utils/iterators/collatz.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/// Collatz sequence iterator.
pub struct Collatz {
num: i64,
done: bool,
}
impl Collatz {
pub fn new(num: i64) -> Collatz {
Collatz { num, done: false }
}
}
impl Iterator for Collatz {
type Item = i64;
fn next(&mut self) -> Option<i64> {
if self.done {
return None;
}
let num = self.num;
self.num = if self.num % 2 == 0 {
self.num / 2
} else {
3 * self.num + 1
};
self.done = num == 1;
Some(num)
}
}


46 changes: 46 additions & 0 deletions src/utils/iterators/continued_fraction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::utils;

/// Generate the continued fraction representation of the square root of a
/// number. The elements generated after the first shall constitute the
/// repeating terms in the continued fraction.
pub struct ContinuedFraction {
num: i64,
a0: i64,
numerator_addend: i64,
denominator: i64,
}
impl ContinuedFraction {
pub fn new(num: i64) -> ContinuedFraction {
ContinuedFraction {
num,
a0: utils::isqrt(num),
numerator_addend: 0,
denominator: 1,
}
}
}
impl Iterator for ContinuedFraction {
type Item = i64;
fn next(&mut self) -> Option<i64> {
// This will happen if the given number was a perfect square. We will
// also use this as the condition for detecting repeating terms.
if self.denominator == 0 {
return None;
}

// If a part of the continued fraction is
// (num.sqrt() + numerator_addend) / denominator
// then the next term of the continued fraction, `numerator_addend` and
// `denominator` can be found using a recurrence relation.
let a = (self.a0 + self.numerator_addend) / self.denominator;
self.numerator_addend = a * self.denominator - self.numerator_addend;
self.denominator = (self.num - self.numerator_addend.pow(2)) / self.denominator;

// When this happens, the terms will start repeating.
if a == self.a0 * 2 {
self.denominator = 0;
}
Some(a)
}
}

27 changes: 27 additions & 0 deletions src/utils/iterators/cubes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

/// Cubes iterator. Generates cubes of integers without multiplication or
/// exponentiation.
pub struct Cubes {
increment: i64,
offset: i64,
num: i64,
}
impl Cubes {
pub fn new() -> Cubes {
Cubes {
increment: 6,
offset: 1,
num: 0,
}
}
}
impl Iterator for Cubes {
type Item = i64;
fn next(&mut self) -> Option<i64> {
self.num += self.offset;
self.offset += self.increment;
self.increment += 6;
Some(self.num)
}
}

24 changes: 24 additions & 0 deletions src/utils/iterators/digits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// Digits iterator. Generates the decimal digits of a number from least
/// significant to most significant. Positive numbers only!
pub struct Digits {
num: i64,
}
impl Digits {
pub fn new(num: i64) -> Digits {
Digits { num }
}
}
impl Iterator for Digits {
type Item = i64;
fn next(&mut self) -> Option<i64> {
if self.num == 0 {
None
} else {
let digit = self.num % 10;
self.num /= 10;
Some(digit)
}
}
}


45 changes: 45 additions & 0 deletions src/utils/iterators/divisors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::utils;

/// Divisors iterator. Generates all divisors of a number in an unspecified
/// order. Positive numbers only!
pub struct Divisors {
dividend: i64,
limit: i64,
current: i64,
other: i64,
}
impl Divisors {
pub fn new(dividend: i64) -> Divisors {
Divisors {
dividend,
limit: utils::isqrt(dividend),
current: 0,
other: 0,
}
}
}
impl Iterator for Divisors {
type Item = i64;
fn next(&mut self) -> Option<i64> {
if self.other > 0 {
let other = self.other;
self.other = 0;
return Some(other);
}
loop {
self.current += 1;
if self.current > self.limit {
return None;
}
if self.dividend % self.current == 0 {
let other = self.dividend / self.current;
if other != self.current {
self.other = other;
}
return Some(self.current);
}
}
}
}


18 changes: 18 additions & 0 deletions src/utils/iterators/fibonacci.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// Fibonacci sequence iterator.
pub struct Fibonacci {
a: i64,
b: i64,
}
impl Fibonacci {
pub fn new(a: i64, b: i64) -> Fibonacci {
Fibonacci { a, b }
}
}
impl Iterator for Fibonacci {
type Item = i64;
fn next(&mut self) -> Option<i64> {
let a = self.a;
(self.a, self.b) = (self.b, self.a + self.b);
Some(a)
}
}
49 changes: 49 additions & 0 deletions src/utils/iterators/polygonal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

/// Triangular, pentagonal, hexagonal, etc. number iterator. Specify the
/// number of sides of the polygon as the argument to the constructor.
pub struct Polygonal {
increment: i64,
offset: i64,
num: i64,
}
impl Polygonal {
pub fn new(sides: i64) -> Polygonal {
Polygonal {
increment: sides - 2,
offset: 1,
num: 0,
}
}
/// Find the index at which the given number would appear in a sequence of
/// polygonal numbers (if it is a polygonal number).
///
/// * `sides` - Number of sides of the polygon the sequence is based on.
/// * `num` - Number whose index is to be found.
///
/// -> Index.
pub fn invert(sides: i64, num: i64) -> Result<i64, i64> {
// A polygonal number is a quadratic function of the index it appears
// at. Solve for the positive root of the corresponding quadratic
// equation.
let a = sides - 2;
let b = 4 - sides;
let c = -2 * num;
let discriminant = b.pow(2) - 4 * a * c;
let idx = (-b as f64 + (discriminant as f64).sqrt()) / (2.0 * a as f64);
let idx_rounded = idx.round() as i64;
if idx.fract() == 0.0 {
Ok(idx_rounded)
} else {
Err(idx_rounded)
}
}
}
impl Iterator for Polygonal {
type Item = i64;
fn next(&mut self) -> Option<i64> {
self.num += self.offset;
self.offset += self.increment;
Some(self.num)
}
}

34 changes: 34 additions & 0 deletions src/utils/iterators/potential_primes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// Potential prime numbers. Generates some small prime numbers and numbers
/// coprime to 30. Used for wheel factorisation with 2, 3 and 5.
pub struct PotentialPrimes {
limit: i64,
num: i64,
offset: std::iter::Cycle<std::array::IntoIter<i64, 8>>,
}
impl PotentialPrimes {
pub fn new(limit: i64) -> PotentialPrimes {
PotentialPrimes {
limit,
num: 1,
offset: [4, 2, 4, 2, 4, 6, 2, 6].into_iter().cycle(),
}
}
}
impl Iterator for PotentialPrimes {
type Item = i64;
fn next(&mut self) -> Option<i64> {
self.num += match self.num {
1 => 1,
2 => 1,
3 | 5 => 2,
_ => self.offset.next().unwrap(),
};
if self.num > self.limit {
None
} else {
Some(self.num)
}
}
}


41 changes: 41 additions & 0 deletions src/utils/iterators/prime_divisors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use crate::utils;

/// Prime divisors iterator. Generates all prime divisors of a number in
/// ascending order. Positive numbers only!
pub struct PrimeDivisors {
// If I actually find all prime numbers to iterate over (instead of just
// using potential prime numbers), performance drops significantly.
potential_primes: utils::PotentialPrimes,
num: i64,
}
impl PrimeDivisors {
pub fn new(num: i64) -> PrimeDivisors {
PrimeDivisors {
potential_primes: utils::PotentialPrimes::new(num),
num,
}
}
}
impl Iterator for PrimeDivisors {
type Item = (i64, u32);
fn next(&mut self) -> Option<(i64, u32)> {
loop {
let potential_prime = match self.potential_primes.next() {
Some(potential_prime) if potential_prime <= self.num => potential_prime,
_ => return None,
};
let mut power = 0;
while self.num % potential_prime == 0 {
self.num /= potential_prime;
power += 1;
}
// Since I divide out the number by all potential primes I find,
// the potential primes I do find are actually prime.
if power > 0 {
return Some((potential_prime, power));
}
}
}
}


Loading

0 comments on commit f77d046

Please sign in to comment.