-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathcompute_totient.rs
More file actions
128 lines (109 loc) · 3.31 KB
/
Copy pathcompute_totient.rs
File metadata and controls
128 lines (109 loc) · 3.31 KB
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Totient function for
// all numbers smaller than
// or equal to n.
// Computes and prints
// totient of all numbers
// smaller than or equal to n
use std::vec;
pub fn compute_totient(n: usize) -> Vec<usize> {
if n == 0 {
return vec![];
}
let mut phi: Vec<usize> = (0..=n).collect();
for p in 2..=n {
if phi[p] == p {
phi[p] = p - 1;
let step = p;
for i in ((2 * p)..=n).step_by(step) {
phi[i] = (phi[i] / p) * (p - 1);
}
}
}
phi[1..].to_vec()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_1() {
assert_eq!(
compute_totient(12),
vec![1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4]
);
}
#[test]
fn test_2() {
assert_eq!(compute_totient(7), vec![1, 1, 2, 2, 4, 2, 6]);
}
#[test]
fn test_3() {
assert_eq!(compute_totient(4), vec![1, 1, 2, 2]);
}
#[test]
fn test_edge_cases() {
assert_eq!(compute_totient(0), vec![]);
assert_eq!(compute_totient(1), vec![1]);
assert_eq!(compute_totient(2), vec![1, 1]);
}
#[test]
fn test_prime_numbers() {
// For prime p, φ(p) = p-1
assert_eq!(compute_totient(13), vec![1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 2, 12]);
assert_eq!(compute_totient(17).last(), Some(&16));
}
#[test]
fn test_powers_of_two() {
// For 2^k, φ(2^k) = 2^(k-1)
assert_eq!(compute_totient(8), vec![1, 1, 2, 2, 4, 2, 6, 4]);
// Verify φ(8) = 4
assert_eq!(compute_totient(8)[7], 4);
}
#[test]
fn test_small_values() {
let result = compute_totient(10);
// Known values: φ(1)=1, φ(2)=1, φ(3)=2, φ(4)=2, φ(5)=4,
// φ(6)=2, φ(7)=6, φ(8)=4, φ(9)=6, φ(10)=4
assert_eq!(result, vec![1, 1, 2, 2, 4, 2, 6, 4, 6, 4]);
}
#[test]
fn test_property_multiplicative() {
// φ(mn) = φ(m) * φ(n) when m,n are coprime
let result = compute_totient(15); // 15 = 3 * 5
// φ(3)=2, φ(5)=4, so φ(15)=8
assert_eq!(result[14], 8);
}
#[test]
fn test_larger_n() {
let result = compute_totient(20);
assert_eq!(result.len(), 20);
// Spot check known values
assert_eq!(result[0], 1); // φ(1)
assert_eq!(result[6], 6); // φ(7)
assert_eq!(result[8], 6); // φ(9)
assert_eq!(result[11], 4); // φ(12)
assert_eq!(result[19], 8); // φ(20)
}
#[test]
fn test_consistency() {
// Test that φ(n) ≤ n-1 for n > 1
for n in 2..=50 {
let result = compute_totient(n);
assert!(result[n-1] <= n-1, "φ({}) = {} exceeds {}", n, result[n-1], n-1);
}
}
#[test]
fn test_sieve_correctness() {
// Compare with direct computation for small n
fn direct_phi(n: usize) -> usize {
(1..=n).filter(|&x| gcd(x, n) == 1).count()
}
fn gcd(a: usize, b: usize) -> usize {
if b == 0 { a } else { gcd(b, a % b) }
}
for n in 1..=20 {
let sieve_result = compute_totient(n);
let direct_result: Vec<usize> = (1..=n).map(direct_phi).collect();
assert_eq!(sieve_result, direct_result, "Failed for n={}", n);
}
}
}