nekolib/math/euler_phi.rs
1//! Euler の $\\varphi$ 関数。
2
3use super::factors;
4
5use factors::Factors;
6
7/// Euler の $\\varphi$ 関数。
8///
9/// $n$ 以下の自然数のうち、$n$ と互いに素であるものの個数を返す。$1$
10/// と $1$ は互いに素であることに注意。
11///
12/// # Note
13/// 素数冪 $p^k$, $p\'^{k\'}$ ($p\\ne p\'$) について
14/// $\\varphi(p^k p\'^{k\'}) = \\varphi(p^k)\\varphi(p\'^{k\'})$
15/// が成り立つ。また、$\\varphi(p^k) = \\varphi^{k-1}\\cdot(p-1)$ が成り立つ。
16///
17/// # Complexity
18/// $O(\\sqrt{n})$ time.
19///
20/// # Examples
21/// ```
22/// use nekolib::math::EulerPhi;
23///
24/// assert_eq!(1_u64.euler_phi(), 1);
25/// assert_eq!(60_u64.euler_phi(), 16);
26/// ```
27pub trait EulerPhi {
28 fn euler_phi(self) -> Self;
29}
30
31macro_rules! impl_uint {
32 ($t:ty) => {
33 impl EulerPhi for $t {
34 fn euler_phi(self) -> Self {
35 self.factors().map(|(p, e)| p.pow(e - 1) * (p - 1)).product()
36 }
37 }
38 };
39 ( $($t:ty)* ) => { $(impl_uint!($t);)* };
40}
41
42impl_uint!(u8 u16 u32 u64 u128 usize);
43
44#[test]
45fn test_naive() {
46 use gcd::Gcd;
47 let n = 100_usize;
48 for i in 1..=n {
49 let phi = (1..=i).filter(|&j| i.gcd(j) == 1).count();
50 assert_eq!(i.euler_phi(), phi);
51 }
52}