pub fn totient(n: i64) -> i64 {
if n == 0 {
return 0;
}
if n == 1 {
return 1;
}
let mut n_abs = n.abs();
let mut result = n_abs;
let original = n_abs;
if n_abs % 2 == 0 {
while n_abs % 2 == 0 {
n_abs /= 2;
}
result -= result / 2;
}
let mut i = 3i64;
while i * i <= original {
if n_abs % i == 0 {
while n_abs % i == 0 {
n_abs /= i;
}
result -= result / i;
}
i += 2;
}
if n_abs > 1 {
result -= result / n_abs;
}
result
}
pub fn totient_i128(n: i128) -> i128 {
if n == 0 {
return 0;
}
if n == 1 {
return 1;
}
let mut n_abs = n.abs();
let mut result = n_abs;
let original = n_abs;
if n_abs % 2 == 0 {
while n_abs % 2 == 0 {
n_abs /= 2;
}
result -= result / 2;
}
let mut i = 3i128;
while i * i <= original {
if n_abs % i == 0 {
while n_abs % i == 0 {
n_abs /= i;
}
result -= result / i;
}
i += 2;
}
if n_abs > 1 {
result -= result / n_abs;
}
result
}
pub fn totient_from_factors(n: i64) -> Option<i64> {
if n == 0 {
return Some(0);
}
if n == 1 {
return Some(1);
}
let n_abs = n.abs();
let factors = prime_factors(n_abs)?;
let mut result = n_abs;
for prime in factors {
result = (result / prime) * (prime - 1);
}
Some(result)
}
fn prime_factors(n: i64) -> Option<Vec<i64>> {
if n == 0 {
return None;
}
if n == 1 {
return Some(Vec::new());
}
let mut n = n;
let mut factors = Vec::new();
while n % 2 == 0 {
if factors.is_empty() || factors.last() != Some(&2) {
factors.push(2);
}
n /= 2;
}
let mut i = 3i64;
while i * i <= n {
while n % i == 0 {
if factors.last() != Some(&i) {
factors.push(i);
}
n /= i;
}
i += 2;
}
if n > 1 {
factors.push(n);
}
Some(factors)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_totient() {
assert_eq!(totient(1), 1);
assert_eq!(totient(2), 1);
assert_eq!(totient(3), 2);
assert_eq!(totient(5), 4);
assert_eq!(totient(7), 6);
assert_eq!(totient(11), 10);
assert_eq!(totient(4), 2); assert_eq!(totient(8), 4); assert_eq!(totient(9), 6); assert_eq!(totient(27), 18);
assert_eq!(totient(10), 4); assert_eq!(totient(14), 6); assert_eq!(totient(15), 8);
assert_eq!(totient(30), 8);
}
#[test]
fn test_totient_negative() {
assert_eq!(totient(-7), 6);
assert_eq!(totient(-10), 4);
}
#[test]
fn test_totient_i128() {
assert_eq!(totient_i128(1), 1);
assert_eq!(totient_i128(7), 6);
assert_eq!(totient_i128(30), 8);
assert_eq!(totient_i128(-7), 6);
}
#[test]
fn test_prime_factors() {
assert_eq!(prime_factors(1), Some(vec![]));
assert_eq!(prime_factors(2), Some(vec![2]));
assert_eq!(prime_factors(12), Some(vec![2, 3]));
assert_eq!(prime_factors(30), Some(vec![2, 3, 5]));
assert_eq!(prime_factors(0), None);
}
#[test]
fn test_totient_from_factors() {
assert_eq!(totient_from_factors(1), Some(1));
assert_eq!(totient_from_factors(7), Some(6));
assert_eq!(totient_from_factors(10), Some(4));
assert_eq!(totient_from_factors(30), Some(8));
}
}