generated from mschoi/template
Add new problem modules and utility functions for Euler and Rosalind challenges
- Introduced `prob700`, `prob808`, and `prob816` modules for new problem implementations in the Project Euler series. - Added utility functions for calculating Euler coins and their sums, as well as methods for finding reversible primes and calculating shortest distances in a modular context. - Updated the `mod.rs` files to include the new problem modules in both the Project Euler and Rosalind sections. - Enhanced the `integer` and `modulo` utility modules with new functions for coprimality checks and modular multiplication. - Included unit tests for the new functionalities to ensure correctness and reliability. - Refactored existing tests for consistency in the `finding_protein_motif` module.
This commit is contained in:
@@ -4,7 +4,10 @@ pub mod prob497;
|
||||
pub mod prob61;
|
||||
pub mod prob650;
|
||||
pub mod prob66;
|
||||
pub mod prob700;
|
||||
pub mod prob719;
|
||||
pub mod prob808;
|
||||
pub mod prob816;
|
||||
pub mod prob885;
|
||||
pub mod prob932;
|
||||
pub mod prob934;
|
||||
|
||||
198
src/project_euler/prob700.rs
Normal file
198
src/project_euler/prob700.rs
Normal file
@@ -0,0 +1,198 @@
|
||||
use num_integer::{Integer, gcd};
|
||||
use std::collections::HashSet;
|
||||
|
||||
fn euler_inverse(p: i64, q: i64) -> i64 {
|
||||
let g = gcd(p, q) as i64;
|
||||
if g != 1 {
|
||||
panic!("p and q are not coprime");
|
||||
}
|
||||
|
||||
let (mut rn, mut rn1) = (p, q);
|
||||
let (mut an, mut an1) = (1, 0);
|
||||
while rn1 != 0 {
|
||||
let (quot, rem) = rn.div_rem(&rn1);
|
||||
let temp = an1;
|
||||
an1 = an - quot * an1;
|
||||
an = temp;
|
||||
rn = rn1;
|
||||
rn1 = rem;
|
||||
}
|
||||
an
|
||||
}
|
||||
|
||||
fn naive_eulercoins(p: i64, q: i64) -> Vec<i64> {
|
||||
let mut coins = vec![p];
|
||||
let mut current = p;
|
||||
while current != 1 {
|
||||
current = (current + p) % q;
|
||||
if ¤t < coins.last().unwrap() {
|
||||
coins.push(current);
|
||||
}
|
||||
}
|
||||
coins
|
||||
}
|
||||
|
||||
pub fn naive_eulercoins_sum(p: i64, q: i64) -> i64 {
|
||||
let coins = naive_eulercoins(p, q);
|
||||
coins.iter().sum()
|
||||
}
|
||||
|
||||
pub fn eulercoins(p: i64, q: i64) -> HashSet<i64> {
|
||||
let inv = euler_inverse(p, q);
|
||||
|
||||
// for left index, large number
|
||||
let mut left_index = 0;
|
||||
let mut left_coin = i64::MAX;
|
||||
let mut test_number = 0;
|
||||
let left_step = p;
|
||||
|
||||
// for right index, small number
|
||||
let mut right_index = i64::MAX;
|
||||
let mut right_coin = 0;
|
||||
let mut test_index = 0;
|
||||
let right_step = inv;
|
||||
|
||||
let mut coins = HashSet::new();
|
||||
let mut bigstep;
|
||||
while left_index < right_index {
|
||||
left_index += 1;
|
||||
test_number = (test_number + left_step).rem_euclid(q);
|
||||
if test_number < left_coin {
|
||||
left_coin = test_number;
|
||||
|
||||
if coins.contains(&left_coin) {
|
||||
break;
|
||||
}
|
||||
coins.insert(left_coin);
|
||||
|
||||
bigstep = (q - test_number) / left_step;
|
||||
test_number += bigstep * left_step;
|
||||
left_index += bigstep;
|
||||
}
|
||||
|
||||
right_coin += 1;
|
||||
test_index = (test_index + right_step).rem_euclid(q);
|
||||
if test_index < right_index {
|
||||
right_index = test_index;
|
||||
|
||||
if coins.contains(&right_coin) {
|
||||
break;
|
||||
}
|
||||
coins.insert(right_coin);
|
||||
|
||||
bigstep = (q - test_index) / right_step;
|
||||
test_index += bigstep * right_step;
|
||||
right_coin += bigstep;
|
||||
}
|
||||
}
|
||||
coins
|
||||
}
|
||||
|
||||
pub fn eulercoins_sum(p: i64, q: i64) -> i64 {
|
||||
let coins = eulercoins(p, q);
|
||||
coins.iter().sum()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::utils::prime::is_prime;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_naive_eulercoins() {
|
||||
assert_eq!(
|
||||
naive_eulercoins_sum(1_983_365_009, 8_977_183_777),
|
||||
6696721770
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_euler_coefficient() {
|
||||
assert_eq!(euler_inverse(3, 2), 1);
|
||||
assert_eq!(euler_inverse(2, 3), -1);
|
||||
|
||||
assert_eq!(euler_inverse(5, 3), -1);
|
||||
assert_eq!(euler_inverse(3, 5), 2);
|
||||
|
||||
assert_eq!(euler_inverse(17, 13), -3);
|
||||
assert_eq!(euler_inverse(13, 17), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eulercoins() {
|
||||
assert_eq!(eulercoins(2, 3), HashSet::from([2, 1]));
|
||||
assert_eq!(eulercoins(3, 5), HashSet::from([1, 3]));
|
||||
assert_eq!(eulercoins(13, 17), HashSet::from([1, 5, 9, 13]));
|
||||
assert_eq!(
|
||||
eulercoins(1_983_365_009, 8_977_183_777),
|
||||
HashSet::from([
|
||||
1_983_365_009,
|
||||
939641268,
|
||||
835558795,
|
||||
731476322,
|
||||
627393849,
|
||||
523311376,
|
||||
419228903,
|
||||
315146430,
|
||||
211063957,
|
||||
106981484,
|
||||
2899011,
|
||||
281923,
|
||||
202142,
|
||||
122361,
|
||||
42580,
|
||||
5379,
|
||||
452,
|
||||
45,
|
||||
43,
|
||||
41,
|
||||
39,
|
||||
37,
|
||||
35,
|
||||
33,
|
||||
31,
|
||||
29,
|
||||
27,
|
||||
25,
|
||||
23,
|
||||
21,
|
||||
19,
|
||||
17,
|
||||
15,
|
||||
13,
|
||||
11,
|
||||
9,
|
||||
7,
|
||||
5,
|
||||
3,
|
||||
1,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eulercoins_many_case() {
|
||||
for p in 5..=100 {
|
||||
for q in p + 1..=200 {
|
||||
if !is_prime(p as usize) || !is_prime(q as usize) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let coins = eulercoins(p, q);
|
||||
let naive_coins = naive_eulercoins(p, q);
|
||||
assert_eq!(coins, HashSet::from_iter(naive_coins.into_iter()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eulercoins_sum() {
|
||||
assert_eq!(eulercoins_sum(1_983_365_009, 8_977_183_777), 6696721770);
|
||||
|
||||
assert_eq!(
|
||||
eulercoins_sum(1_504_170_715_041_707, 4_503_599_627_370_517),
|
||||
1517926517777556
|
||||
);
|
||||
}
|
||||
}
|
||||
149
src/project_euler/prob808.rs
Normal file
149
src/project_euler/prob808.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
use crate::utils::integer::is_square;
|
||||
use crate::utils::prime::{is_prime, prime_iter};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn is_revserible(prime: u64) -> bool {
|
||||
let rev_square = (prime * prime)
|
||||
.to_string()
|
||||
.chars()
|
||||
.rev()
|
||||
.collect::<String>()
|
||||
.parse::<u64>()
|
||||
.unwrap();
|
||||
|
||||
is_square(rev_square) && rev_square != prime * prime && is_prime(rev_square.isqrt())
|
||||
}
|
||||
|
||||
pub fn reverse(n: u64) -> u64 {
|
||||
n.to_string()
|
||||
.chars()
|
||||
.rev()
|
||||
.collect::<String>()
|
||||
.parse::<u64>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn length(n: u64) -> usize {
|
||||
n.to_string().len()
|
||||
}
|
||||
|
||||
pub fn find_reversible_primes_in_range(n: usize) -> Vec<u64> {
|
||||
let mut cache_rev_squares: HashMap<u64, u64> = HashMap::new();
|
||||
let mut reversible_prime_squares = Vec::new();
|
||||
|
||||
let mut square;
|
||||
for prime in prime_iter::<u64>(n) {
|
||||
square = prime * prime;
|
||||
if let Some(rev_square) = cache_rev_squares.remove(&square) {
|
||||
reversible_prime_squares.push(rev_square);
|
||||
reversible_prime_squares.push(square);
|
||||
} else if length(square) % 2 == 1 {
|
||||
let rev_square = reverse(square);
|
||||
if rev_square != square && (rev_square % 10 == 1 || rev_square % 10 == 9) {
|
||||
cache_rev_squares.insert(rev_square, square);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reversible_prime_squares.sort();
|
||||
reversible_prime_squares
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_is_revserible() {
|
||||
assert_eq!(is_revserible(3), false);
|
||||
assert_eq!(is_revserible(5), false);
|
||||
assert_eq!(is_revserible(7), false);
|
||||
assert_eq!(is_revserible(11), false);
|
||||
assert_eq!(is_revserible(13), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_reversible_primes_in_range() {
|
||||
assert_eq!(
|
||||
find_reversible_primes_in_range(500_000_000),
|
||||
vec![
|
||||
169,
|
||||
961,
|
||||
12769,
|
||||
96721,
|
||||
1042441,
|
||||
1062961,
|
||||
1216609,
|
||||
1442401,
|
||||
1692601,
|
||||
9066121,
|
||||
121066009,
|
||||
900660121,
|
||||
12148668841,
|
||||
12367886521,
|
||||
12568876321,
|
||||
14886684121,
|
||||
1000422044521,
|
||||
1002007006009,
|
||||
1020506060401,
|
||||
1040606050201,
|
||||
1210684296721,
|
||||
1212427816609,
|
||||
1212665666521,
|
||||
1214648656321,
|
||||
1234367662441,
|
||||
1236568464121,
|
||||
1254402240001,
|
||||
1256665662121,
|
||||
1276924860121,
|
||||
1442667634321,
|
||||
9006007002001,
|
||||
9066187242121,
|
||||
100042424498641,
|
||||
100222143232201,
|
||||
100240164024001,
|
||||
100402824854641,
|
||||
100420461042001,
|
||||
102012282612769,
|
||||
102014060240401,
|
||||
102232341222001,
|
||||
104042060410201,
|
||||
121002486012769,
|
||||
121264386264121,
|
||||
121462683462121,
|
||||
123212686214641,
|
||||
146412686212321,
|
||||
146458428204001,
|
||||
146894424240001,
|
||||
967210684200121,
|
||||
967216282210201,
|
||||
10020032222212321,
|
||||
10022014702860169,
|
||||
10201204627026169,
|
||||
10203042928272769,
|
||||
10424432666212321,
|
||||
10444842248400121,
|
||||
12100484224844401,
|
||||
12100662429066121,
|
||||
12102442783276609,
|
||||
12104622861462121,
|
||||
12120294922868521,
|
||||
12122012862600169,
|
||||
12122034882612769,
|
||||
12126416822640121,
|
||||
12144284865634321,
|
||||
12166092426600121,
|
||||
12321222223002001,
|
||||
12321266623442401,
|
||||
12343656848244121,
|
||||
12586822949202121,
|
||||
90667238724420121,
|
||||
96100626821022121,
|
||||
96106820741022001,
|
||||
96162072640210201,
|
||||
96721628843022121,
|
||||
96727282924030201
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
135
src/project_euler/prob816.rs
Normal file
135
src/project_euler/prob816.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
use crate::utils::modulo::modulo_mul;
|
||||
|
||||
fn make_point_array(s0: u64, n: usize, modulus: u64) -> Vec<(u64, u64)> {
|
||||
let mut s2n = s0;
|
||||
let mut s2n1 = modulo_mul(s0, s0, modulus);
|
||||
let mut points = vec![(s2n, s2n1)];
|
||||
for _ in 1..n {
|
||||
s2n = modulo_mul(s2n1, s2n1, modulus);
|
||||
s2n1 = modulo_mul(s2n, s2n, modulus);
|
||||
points.push((s2n, s2n1));
|
||||
}
|
||||
points
|
||||
}
|
||||
|
||||
pub fn naive_shortest_distance(s0: u64, n: usize, modulus: u64) -> String {
|
||||
let points = make_point_array(s0, n, modulus);
|
||||
let mut min_distance_square = i64::MAX;
|
||||
for i in 0..n {
|
||||
for j in i + 1..n {
|
||||
let dx1 = (points[i].0 as i64 - points[j].0 as i64).abs();
|
||||
let dx2 = (points[i].1 as i64 - points[j].1 as i64).abs();
|
||||
let distance_square = dx1 * dx1 + dx2 * dx2;
|
||||
if distance_square < min_distance_square {
|
||||
min_distance_square = distance_square;
|
||||
}
|
||||
}
|
||||
}
|
||||
format!("{:.9}", (min_distance_square as f64).sqrt())
|
||||
}
|
||||
|
||||
pub fn dc_shortest_distance(points: &[(u64, u64)]) -> i64 {
|
||||
let n = points.len();
|
||||
if n <= 3 {
|
||||
let mut min_distance_square = i64::MAX;
|
||||
for i in 0..n {
|
||||
for j in i + 1..n {
|
||||
let dx1 = points[i].0 as i64 - points[j].0 as i64;
|
||||
let dx2 = points[i].1 as i64 - points[j].1 as i64;
|
||||
let distance_square = dx1 * dx1 + dx2 * dx2;
|
||||
if distance_square < min_distance_square {
|
||||
min_distance_square = distance_square;
|
||||
}
|
||||
}
|
||||
}
|
||||
return min_distance_square;
|
||||
}
|
||||
|
||||
let mid = n / 2;
|
||||
let min_from_left = dc_shortest_distance(&points[..mid]);
|
||||
let min_from_right = dc_shortest_distance(&points[mid..]);
|
||||
let mut min_distance_square = min_from_left.min(min_from_right);
|
||||
let min_distance = min_distance_square.isqrt() as u64 + 1;
|
||||
|
||||
let mid_x = points[mid].0;
|
||||
let mut strip = vec![points[mid]];
|
||||
let mut cursor = mid - 1;
|
||||
while mid_x < points[cursor].0 + min_distance {
|
||||
strip.push(points[cursor]);
|
||||
cursor = match cursor.checked_sub(1) {
|
||||
Some(c) => c,
|
||||
None => break,
|
||||
};
|
||||
}
|
||||
cursor = mid + 1;
|
||||
while cursor < n && points[cursor].0 < mid_x + min_distance {
|
||||
strip.push(points[cursor]);
|
||||
cursor += 1;
|
||||
}
|
||||
|
||||
strip.sort_by_key(|p| p.1);
|
||||
let length = strip.len();
|
||||
for i in 0..length {
|
||||
cursor = i + 1;
|
||||
while cursor < length && strip[cursor].1 < min_distance + strip[i].1 {
|
||||
let dx1 = strip[i].0 as i64 - strip[cursor].0 as i64;
|
||||
let dx2 = strip[i].1 as i64 - strip[cursor].1 as i64;
|
||||
let distance_square = dx1 * dx1 + dx2 * dx2;
|
||||
if distance_square < min_distance_square {
|
||||
min_distance_square = distance_square;
|
||||
}
|
||||
cursor += 1;
|
||||
}
|
||||
}
|
||||
min_distance_square
|
||||
}
|
||||
|
||||
pub fn shortest_distance(s0: u64, n: usize, modulus: u64) -> String {
|
||||
let mut points = make_point_array(s0, n, modulus);
|
||||
points.sort_by_key(|p| p.0);
|
||||
let min_distance_square = dc_shortest_distance(&points);
|
||||
format!("{:.9}", (min_distance_square as f64).sqrt())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_make_point_array() {
|
||||
let points = make_point_array(2, 10, 1000);
|
||||
assert_eq!(points.len(), 10);
|
||||
assert_eq!(
|
||||
points,
|
||||
vec![
|
||||
(2, 4),
|
||||
(16, 256),
|
||||
(536, 296),
|
||||
(616, 456),
|
||||
(936, 96),
|
||||
(216, 656),
|
||||
(336, 896),
|
||||
(816, 856),
|
||||
(736, 696),
|
||||
(416, 56)
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_naive_shortest_distance() {
|
||||
assert_eq!(
|
||||
naive_shortest_distance(290797, 14, 50515093),
|
||||
"546446.466846479"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shortest_distance() {
|
||||
assert_eq!(shortest_distance(290797, 14, 50515093), "546446.466846479");
|
||||
assert_eq!(
|
||||
shortest_distance(290797, 2_000_000, 50515093),
|
||||
"20.880613018"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ mod tests {
|
||||
let protein = "MRASRPVVHPVEAPPPAALAVAAAAVAVEAGVGAGGGAAAHGGENAQPRGVRMKDPPGAPGTPGGLGLRLVQAFFAAAALAVMASTDDFPSVSAFCYLVAAAILQCLWSLSLAVVDIYALLVKRSLRNPQAVCIFTIGDGITGTLTLGAACASAGITVLIGNDLNICANNHCASFETATAMAFISWFALAPSCVLNFWSMASR";
|
||||
let motif = "N{P}[ST]{P}";
|
||||
let positions = find_protein_motif(protein, motif);
|
||||
assert_eq!(positions, vec![]);
|
||||
assert_eq!(positions, Vec::<usize>::new());
|
||||
|
||||
let protein = "GCATGATACATG";
|
||||
let motif = "CAT";
|
||||
@@ -66,7 +66,7 @@ mod tests {
|
||||
|
||||
let uniprot_id = "A2Z669";
|
||||
let positions = find_protein_motif_in_uniprot(uniprot_id, motif);
|
||||
assert_eq!(positions, vec![]);
|
||||
assert_eq!(positions, Vec::<usize>::new());
|
||||
|
||||
sleep(Duration::from_millis(10));
|
||||
|
||||
|
||||
@@ -3,4 +3,5 @@ pub mod enumerating_gene_orders;
|
||||
pub mod finding_protein_motif;
|
||||
pub mod inferring_mrna_from_protein;
|
||||
pub mod open_reading_frames;
|
||||
pub mod rna_secondary_structure;
|
||||
pub mod rna_splicing;
|
||||
|
||||
0
src/rosalind/rna_secondary_structure.rs
Normal file
0
src/rosalind/rna_secondary_structure.rs
Normal file
@@ -1,4 +1,4 @@
|
||||
use num::integer::{Integer, Roots};
|
||||
use num::integer::{Integer, Roots, gcd};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
pub fn is_square<T>(n: T) -> bool
|
||||
@@ -9,6 +9,13 @@ where
|
||||
s * s == n
|
||||
}
|
||||
|
||||
pub fn is_coprime<T>(a: T, b: T) -> bool
|
||||
where
|
||||
T: Integer + Copy,
|
||||
{
|
||||
gcd(a, b) == T::one()
|
||||
}
|
||||
|
||||
pub fn has_split_of_sum(n: usize, sum: usize) -> Option<Vec<usize>> {
|
||||
match n.cmp(&sum) {
|
||||
Ordering::Less => None,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use num::traits::{Euclid, PrimInt};
|
||||
use num::{
|
||||
bigint::{BigInt, ToBigInt},
|
||||
traits::{Euclid, PrimInt},
|
||||
};
|
||||
|
||||
pub fn checked_modulo_add<T: PrimInt + Euclid>(a: T, b: T, modulo: T) -> T {
|
||||
pub fn modulo_add<T: PrimInt + Euclid>(a: T, b: T, modulo: T) -> T {
|
||||
match a.checked_add(&b) {
|
||||
Some(c) => c % modulo,
|
||||
None => {
|
||||
@@ -16,23 +19,57 @@ pub fn checked_modulo_add<T: PrimInt + Euclid>(a: T, b: T, modulo: T) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modulo_mul<T>(a: T, b: T, modulo: T) -> T
|
||||
where
|
||||
T: PrimInt + Euclid + ToBigInt,
|
||||
BigInt: std::ops::Rem<T>,
|
||||
{
|
||||
match a.checked_mul(&b) {
|
||||
Some(c) => c.rem_euclid(&modulo),
|
||||
None => {
|
||||
let a_big = a.to_bigint().unwrap();
|
||||
let b_big = b.to_bigint().unwrap();
|
||||
let modulo_big = modulo.to_bigint().unwrap();
|
||||
let c_big = a_big * b_big;
|
||||
let c = c_big.rem_euclid(&modulo_big);
|
||||
T::from(c.to_u32_digits().1[0]).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_checked_modulo_add() {
|
||||
fn test_modulo_add() {
|
||||
assert_eq!(
|
||||
checked_modulo_add::<u32>(1_000_000_000, 4_000_000_000, 1_543_545_676),
|
||||
modulo_add::<u32>(1_000_000_000, 4_000_000_000, 1_543_545_676),
|
||||
369_362_972
|
||||
);
|
||||
assert_eq!(
|
||||
checked_modulo_add::<i32>(1_000_000_000, 2_000_000_000, 1_543_545_676),
|
||||
modulo_add::<i32>(1_000_000_000, 2_000_000_000, 1_543_545_676),
|
||||
1_456_454_324
|
||||
);
|
||||
assert_eq!(
|
||||
checked_modulo_add::<i32>(-1_000_000_000, -2_000_000_000, 1_543_545_676),
|
||||
modulo_add::<i32>(-1_000_000_000, -2_000_000_000, 1_543_545_676),
|
||||
87_091_352
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modulo_mul() {
|
||||
assert_eq!(
|
||||
modulo_mul::<u32>(1_000_000_000, 4_000_000_000, 1_543_545_676),
|
||||
866_330_992
|
||||
);
|
||||
assert_eq!(
|
||||
modulo_mul::<i32>(1_000_000_000, 2_000_000_000, 1_543_545_676),
|
||||
433_165_496
|
||||
);
|
||||
assert_eq!(
|
||||
modulo_mul::<i32>(-1_000_000_000, 2_000_000_000, 1_543_545_676),
|
||||
1_110_380_180
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use num::{FromPrimitive, ToPrimitive, Unsigned, integer::Roots, iter::range_inclusive};
|
||||
use num::{FromPrimitive, PrimInt, ToPrimitive, Unsigned, integer::Roots, iter::range_inclusive};
|
||||
|
||||
pub fn is_prime<T>(n: T) -> bool
|
||||
where
|
||||
@@ -18,6 +18,60 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct PrimeSieve<T> {
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
sieve: Vec<bool>,
|
||||
cursor: usize,
|
||||
max: usize,
|
||||
}
|
||||
|
||||
impl<T> PrimeSieve<T>
|
||||
where
|
||||
T: PrimInt + FromPrimitive,
|
||||
{
|
||||
fn new(n: usize) -> Self {
|
||||
Self {
|
||||
_marker: std::marker::PhantomData,
|
||||
sieve: vec![true; n + 1],
|
||||
cursor: 2,
|
||||
max: n,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for PrimeSieve<T>
|
||||
where
|
||||
T: PrimInt + ToPrimitive + FromPrimitive,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while self.cursor <= self.max && !self.sieve[self.cursor] {
|
||||
self.cursor += 1;
|
||||
}
|
||||
|
||||
if self.cursor > self.max {
|
||||
return None;
|
||||
}
|
||||
|
||||
let prime = T::from_usize(self.cursor).unwrap();
|
||||
let end = self.max / self.cursor;
|
||||
(2..=end).for_each(|i| {
|
||||
self.sieve[i * self.cursor] = false;
|
||||
});
|
||||
|
||||
self.cursor += 1;
|
||||
Some(prime)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prime_iter<T>(n: usize) -> impl Iterator<Item = T>
|
||||
where
|
||||
T: PrimInt + ToPrimitive + FromPrimitive,
|
||||
{
|
||||
PrimeSieve::<T>::new(n).into_iter()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -44,4 +98,18 @@ mod tests {
|
||||
assert_eq!(is_prime::<u32>(10000006), false);
|
||||
assert_eq!(is_prime::<u32>(10000019), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prime_sieve() {
|
||||
let mut sieve = PrimeSieve::<i32>::new(20);
|
||||
assert_eq!(sieve.next(), Some(2));
|
||||
assert_eq!(sieve.next(), Some(3));
|
||||
assert_eq!(sieve.next(), Some(5));
|
||||
assert_eq!(sieve.next(), Some(7));
|
||||
assert_eq!(sieve.next(), Some(11));
|
||||
assert_eq!(sieve.next(), Some(13));
|
||||
assert_eq!(sieve.next(), Some(17));
|
||||
assert_eq!(sieve.next(), Some(19));
|
||||
assert_eq!(sieve.next(), None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user