From 00d8b69d3e141d478b0afb420b8405eaa7aa83f1 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Fri, 2 Aug 2024 20:06:05 +0530 Subject: [PATCH] Documented `SieveOfAtkin` --- src/utils/objects/sieve_of_atkin.rs | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/utils/objects/sieve_of_atkin.rs b/src/utils/objects/sieve_of_atkin.rs index 85aad00..9ed3d53 100644 --- a/src/utils/objects/sieve_of_atkin.rs +++ b/src/utils/objects/sieve_of_atkin.rs @@ -13,6 +13,7 @@ pub struct SieveOfAtkin { limit_rounded_isqrt: usize, sieve: Vec, } + impl SieveOfAtkin { // Consecutive differences between coprime residues modulo 60: 1, 7, 11, // 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 49, 53 and 59. @@ -25,7 +26,9 @@ impl SieveOfAtkin { 16, 16, 15, ]; } + impl SieveOfAtkin { + /// Construct the sieve of Atkin up to and including the given number. /// /// * `limit` Non-strict upper bound. @@ -43,6 +46,8 @@ impl SieveOfAtkin { sieve_of_atkin.init(); sieve_of_atkin } + + /// Initialise the sieve of Atkin. fn init(&mut self) { for (delta, shift) in [1, 13, 17, 29, 37, 41, 49, 53] .into_iter() @@ -78,6 +83,12 @@ impl SieveOfAtkin { } } } + + /// Of the prime numbers congruent to 1 modulo 4, find those congruent to + /// `delta` modulo 60. + /// + /// * `delta` Residue. + /// * `shift` Position of `delta` in a list of coprime residues modulo 60. fn algorithm_3_1(&mut self, delta: i32, shift: u8) { for f in 1..=15 { for g in (1..=30).step_by(2) { @@ -88,6 +99,12 @@ impl SieveOfAtkin { } } } + + /// Of the prime numbers congruent to 1 modulo 6, find those congruent to + /// `delta` modulo 60. + /// + /// * `delta` Residue. + /// * `shift` Position of `delta` in a list of coprime residues modulo 60. fn algorithm_3_2(&mut self, delta: i32, shift: u8) { for f in (1..=10).step_by(2) { for g in [2, 4, 8, 10, 14, 16, 20, 22, 26, 28] { @@ -98,6 +115,12 @@ impl SieveOfAtkin { } } } + + /// Of the prime numbers congruent to 11 modulo 12, find those congruent to + /// `delta` modulo 60. + /// + /// * `delta` Residue. + /// * `shift` Position of `delta` in a list of coprime residues modulo 60. fn algorithm_3_3(&mut self, delta: i32, shift: u8) { for (f, gstart) in (1..=10).zip([2, 1].into_iter().cycle()) { for g in (gstart..=30).step_by(2) { @@ -109,6 +132,18 @@ impl SieveOfAtkin { } } } + + /// Starting from a point which generates a prime number congruent to 1 + /// modulo 4 and `delta` modulo 60, find all such prime numbers by tracing + /// the generating curve: + /// + /// 4f2 + g2 = 60h + δ + /// (equivalently: `4f^2 + g^2 = 60h + δ`). + /// + /// * `shift` Position of δ in a list of coprime residues modulo 60. + /// * `f` Starting abscissa. + /// * `g` Starting ordinate. + /// * `h` Multiplier of 60 in the generating curve. fn algorithm_4_1(&mut self, shift: u8, f: i32, g: i32, h: i32) { let (mut x, mut y0, mut k0) = (f as i64, g as i64, h as i64); while k0 < self.sieve.len() as i64 { @@ -129,6 +164,18 @@ impl SieveOfAtkin { } } } + + /// Starting from a point which generates a prime number congruent to 1 + /// modulo 6 and `delta` modulo 60, find all such prime numbers by tracing + /// the generating curve: + /// + /// 3f2 + g2 = 60h + δ + /// (equivalently: `3f^2 + g^2 = 60h + δ`). + /// + /// * `shift` Position of δ in a list of coprime residues modulo 60. + /// * `f` Starting abscissa. + /// * `g` Starting ordinate. + /// * `h` Multiplier of 60 in the generating curve. fn algorithm_4_2(&mut self, shift: u8, f: i32, g: i32, h: i32) { let (mut x, mut y0, mut k0) = (f as i64, g as i64, h as i64); while k0 < self.sieve.len() as i64 { @@ -149,6 +196,18 @@ impl SieveOfAtkin { } } } + + /// Starting from a point which generates a prime number congruent to 11 + /// modulo 12 and `delta` modulo 60, find all such prime numbers by tracing + /// the generating curve: + /// + /// 3f2g2 = 60h + δ + /// (equivalently: `3f^2 - g^2 = 60h + δ`). + /// + /// * `shift` Position of δ in a list of coprime residues modulo 60. + /// * `f` Starting abscissa. + /// * `g` Starting ordinate. + /// * `h` Multiplier of 60 in the generating curve. fn algorithm_4_3(&mut self, shift: u8, f: i32, g: i32, h: i32) { let (mut x, mut y0, mut k0) = (f as i64, g as i64, h as i64); loop { @@ -166,6 +225,10 @@ impl SieveOfAtkin { (k0, x) = (k0 + x + 5, x + 10); } } + + /// Check whether the given number is prime. + /// + /// * `num` pub fn is_prime(&self, num: usize) -> bool { if num < 2 { return false; @@ -179,6 +242,8 @@ impl SieveOfAtkin { } self.sieve[num_div_60] & (1u32 << SieveOfAtkin::SHIFTS[num_mod_60]) as u16 != 0 } + + /// Yield the found prime numbers in order. pub fn iter(&self) -> impl Iterator + '_ { let mut num: usize = 1; let mut offset = SieveOfAtkin::OFFSETS.iter().cycle();