Skip to content

Commit 8942a63

Browse files
committed
add spf
1 parent cb0e6ac commit 8942a63

File tree

4 files changed

+158
-3
lines changed

4 files changed

+158
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "math-comb"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
edition = "2021"
55
authors = ["Ashwin Pugalia"]
66
description = "Math library for Combinatorics, Modular arithmetic & Number Theory utilities."

README.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
Math library for Combinatorics, Modular arithmetic & Prime Factorization.
55

6+
---
7+
68
## Description
79

810
This library provides a collection of mathematical utilities:
@@ -15,17 +17,25 @@ This library provides a collection of mathematical utilities:
1517
- Number Theory:
1618
- Primality checking
1719
- Prime factorization (using the `Pollard-Rho` algorithm)
20+
- Smallest prime factor sieve (SPF)
21+
22+
---
1823

1924
## Installation
2025

2126
Add this crate to your `Cargo.toml`:
2227

2328
```toml
2429
[dependencies]
25-
math-comb = "0.2.2"
30+
math-comb = "0.2.3"
2631
```
2732

33+
---
34+
2835
### Examples
36+
37+
#### Permutations & Combinations (Modular)
38+
2939
```rust
3040
use math_comb::Comb;
3141

@@ -39,6 +49,8 @@ fn main() {
3949
}
4050
```
4151

52+
#### Modular Exponentiation & Inverse
53+
4254
```rust
4355
use math_comb::Modexp;
4456

@@ -54,6 +66,8 @@ fn main() {
5466
}
5567
```
5668

69+
#### Prime factorization & Primality checks
70+
5771
```rust
5872
use math_comb::Prime;
5973

@@ -72,6 +86,29 @@ fn main() {
7286
}
7387
```
7488

89+
#### Smallest Prime Factors (SPF) & Prime Factorization
90+
91+
```rust
92+
use math_comb::Spf;
93+
94+
fn main() {
95+
let spf = Spf::new(
96+
/*max_limit = */ 10000000
97+
);
98+
99+
// Get the smallest prime factor of a number
100+
let number: u64 = 81;
101+
println!("Smallest prime factor of {}: {}", number, spf.get_spf(number)); // Output: Smallest prime factor of 81: 3
102+
103+
// Factorize a number into its prime factors. This is O(logn) since we have precomputed spfs.
104+
let number: u64 = 45;
105+
let factors = spf.factorize(number);
106+
println!("Prime factors of {}: {:?}", number, factors); // Output: Prime factors of 45: [3, 3, 5]
107+
}
108+
```
109+
110+
---
111+
75112
## License
76113

77114
This library is licensed under MIT License.

src/lib.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,91 @@ impl Prime {
5050
}
5151
}
5252

53+
pub struct Spf {
54+
spf_max_limit: usize,
55+
spf: Vec<u64>
56+
}
57+
58+
/// A struct representing the smallest prime factor (SPF) computation.
59+
impl Spf {
60+
/// Creates a new `Spf` instance with a given maximum limit.
61+
///
62+
/// # Arguments
63+
///
64+
/// * `max_limit` - The maximum limit up to which the smallest prime factors are computed.
65+
///
66+
/// # Returns
67+
///
68+
/// A new `Spf` instance with precomputed smallest prime factors up to `max_limit`.
69+
pub fn new(max_limit: usize) -> Spf {
70+
let mut spf = vec![0; max_limit + 1];
71+
for i in 2..=max_limit {
72+
if spf[i] == 0 {
73+
for j in (i..=max_limit).step_by(i) {
74+
if spf[j] == 0 {
75+
spf[j] = i as u64;
76+
}
77+
}
78+
}
79+
}
80+
Spf {
81+
spf_max_limit: max_limit,
82+
spf: spf,
83+
}
84+
}
85+
86+
/// Retrieves the smallest prime factor of a given number.
87+
///
88+
/// # Arguments
89+
///
90+
/// * `x` - The number for which the smallest prime factor is to be retrieved.
91+
///
92+
/// # Returns
93+
///
94+
/// The smallest prime factor of `x`.
95+
///
96+
/// # Panics
97+
///
98+
/// Panics if `x` is greater than the `max_limit` specified during the creation of the `Spf` instance.
99+
pub fn get_spf(&self, x: u64) -> u64 {
100+
if x as usize > self.spf_max_limit {
101+
panic!("x cannot be greater than max_limit!");
102+
}
103+
self.spf[x as usize]
104+
}
105+
106+
/// Factorizes a given number into its prime factors.
107+
///
108+
/// # Arguments
109+
///
110+
/// * `x` - The number to be factorized.
111+
///
112+
/// # Returns
113+
///
114+
/// A vector containing the prime factors of `x`.
115+
///
116+
/// # Panics
117+
///
118+
/// Panics if `x` is greater than the `max_limit` specified during the creation of the `Spf` instance.
119+
///
120+
/// # Complexity
121+
///
122+
/// The factorization process takes O(log n) time after the SPF computation.
123+
pub fn factorize(&self, x: u64) -> Vec<u64> {
124+
if x as usize > self.spf_max_limit {
125+
panic!("x cannot be greater than max_limit!");
126+
}
127+
let mut factors: Vec<u64> = Vec::new();
128+
let mut y: usize = x as usize;
129+
while y != 1 {
130+
factors.push(self.spf[y]);
131+
y /= self.spf[y] as usize;
132+
}
133+
factors.sort();
134+
factors
135+
}
136+
}
137+
53138
/// A struct that provides methods for modular exponentiation and modular inverse calculations.
54139
pub struct Modexp {}
55140

@@ -271,4 +356,37 @@ mod tests {
271356
fn test_composite_mod() {
272357
let comb: Comb = Comb::new(4, 14);
273358
}
359+
360+
#[test]
361+
pub fn test_spf() {
362+
let spf: Spf = Spf::new(10000000);
363+
assert_eq!(spf.get_spf(7), 7);
364+
assert_eq!(spf.get_spf(25), 5);
365+
assert_eq!(spf.get_spf(2491), 47);
366+
assert_eq!(spf.get_spf(10000000), 2);
367+
assert_eq!(spf.get_spf(81), 3);
368+
}
369+
370+
#[test]
371+
fn test_get_factors_via_spf() {
372+
let spf: Spf = Spf::new(10000000);
373+
assert_eq!(spf.factorize(1000429), vec![1000429]);
374+
assert_eq!(spf.factorize(24), vec![2, 2, 2, 3]);
375+
assert_eq!(spf.factorize(45), vec![3, 3, 5]);
376+
assert_eq!(spf.factorize(346789), vec![239, 1451]);
377+
}
378+
379+
#[test]
380+
#[should_panic(expected = "x cannot be greater than max_limit!")]
381+
fn test_spf_factorize_above_limit() {
382+
let spf: Spf = Spf::new(15);
383+
spf.factorize(16);
384+
}
385+
386+
#[test]
387+
#[should_panic(expected = "x cannot be greater than max_limit!")]
388+
fn test_spf_above_limit() {
389+
let spf: Spf = Spf::new(15);
390+
spf.get_spf(16);
391+
}
274392
}

0 commit comments

Comments
 (0)