18.11 Euler Phi Function

Euler's phi function counts how many numbers in a range are coprime to a given integer.

18.11 Euler Phi Function

Euler's phi function counts how many numbers in a range are coprime to a given integer. It appears naturally in modular arithmetic, cryptography, primitive roots, multiplicative functions, and counting problems over residue classes.

The function is usually written as:

φ(n)

It counts the positive integers k such that:

1 ≤ k ≤ n

and:

gcd(k,n) = 1

For example:

φ(9) = 6

because the numbers coprime to 9 are:

1 2 4 5 7 8

The numbers 3, 6, and 9 are excluded because they share a factor with 9.

Problem

Given an integer:

n

compute:

φ(n)

efficiently.

Example:

φ(10) = 4

because the numbers from 1 to 10 that are coprime to 10 are:

1 3 7 9

A direct count using GCD works, but it is too slow for large n or repeated queries.

Direct Counting

The most literal implementation tests every number.

from math import gcd

def phi_naive(n):
    count = 0

    for k in range(1, n + 1):
        if gcd(k, n) == 1:
            count += 1

    return count

Example:

print(phi_naive(10))

Output:

4

Complexity:

O(n log n)

because each GCD computation costs logarithmic time.

This is useful for testing, but not for production algorithms.

Prime Case

If p is prime, every number:

1, 2, ..., p-1

is coprime to p.

Only p itself is not coprime to p.

Therefore:

φ(p) = p - 1

Examples:

φ(5) = 4
φ(7) = 6
φ(13) = 12

This property is central to Fermat's Little Theorem and finite-field arithmetic.

Prime Power Case

Now consider:

n = p^e

where p is prime.

The only numbers not coprime to p^e are multiples of p.

From 1 through p^e, there are:

p^(e-1)

multiples of p.

So:

φ(p^e) = p^e - p^(e-1)

Factor:

φ(p^e) = p^e(1 - 1/p)

Example:

φ(8) = φ(2^3)

There are:

8 - 4 = 4

coprime values:

1 3 5 7

So:

φ(8) = 4

General Formula

If:

n = p₁^e₁ × p₂^e₂ × ... × pₖ^eₖ

then:

φ(n) = n × (1 - 1/p₁) × (1 - 1/p₂) × ... × (1 - 1/pₖ)

The exponents do not appear directly in the product except through the original value of n.

Example:

n = 36 = 2² × 3²

Then:

φ(36) = 36 × (1 - 1/2) × (1 - 1/3)
φ(36) = 36 × 1/2 × 2/3 = 12

The numbers coprime to 36 are:

1 5 7 11 13 17 19 23 25 29 31 35

There are 12 of them.

Computing Phi from Factorization

The formula can be implemented by iterating over distinct prime factors.

def phi(n):
    result = n
    x = n
    p = 2

    while p * p <= x:
        if x % p == 0:
            result -= result // p

            while x % p == 0:
                x //= p

        p += 1

    if x > 1:
        result -= result // x

    return result

Example:

print(phi(36))
print(phi(10))
print(phi(13))

Output:

12
4
12

The update:

result -= result // p

implements multiplication by:

1 - 1/p

without using floating-point arithmetic.

Why Integer Arithmetic Matters

Avoid this implementation style:

result = int(result * (1 - 1 / p))

It introduces floating-point arithmetic into an exact integer problem. For large numbers, rounding can produce incorrect results.

Use:

result -= result // p

This keeps the calculation exact.

Example Walkthrough

Compute:

φ(60)

Factorization:

60 = 2² × 3 × 5

Start:

result = 60

Process prime factor 2:

result = 60 - 60/2 = 30

Process prime factor 3:

result = 30 - 30/3 = 20

Process prime factor 5:

result = 20 - 20/5 = 16

Therefore:

φ(60) = 16

Multiplicativity

Euler's phi function is multiplicative.

If:

gcd(a,b) = 1

then:

φ(ab) = φ(a)φ(b)

Example:

a = 8
b = 9

Since:

gcd(8,9) = 1

we have:

φ(72) = φ(8)φ(9)

Now:

φ(8) = 4
φ(9) = 6

so:

φ(72) = 24

This agrees with the formula:

72 = 2³ × 3²
φ(72) = 72 × (1 - 1/2) × (1 - 1/3) = 24

Euler's Theorem

Euler's phi function controls powers modulo composite moduli.

If:

gcd(a,n) = 1

then:

a^φ(n) ≡ 1 (mod n)

This is Euler's theorem.

For example:

a = 5
n = 8

Since:

gcd(5,8) = 1

and:

φ(8) = 4

we get:

5⁴ ≡ 1 (mod 8)

Check:

625 mod 8 = 1

Fermat's Little Theorem is the special case where n is prime.

Modular Inverses with Phi

Euler's theorem gives another way to compute modular inverses.

If:

gcd(a,n) = 1

then:

a^φ(n) ≡ 1 (mod n)

So:

a × a^(φ(n)-1) ≡ 1 (mod n)

Therefore:

a⁻¹ ≡ a^(φ(n)-1) (mod n)

This is valid for composite moduli too, provided a and n are coprime.

In practice, Extended Euclid is usually faster for a single inverse because it avoids factoring n.

Sieve for Phi Values

If we need φ(x) for every x <= n, we can compute all values with a sieve.

def phi_sieve(n):
    phi = list(range(n + 1))

    for p in range(2, n + 1):
        if phi[p] == p:
            for multiple in range(p, n + 1, p):
                phi[multiple] -= phi[multiple] // p

    return phi

Example:

values = phi_sieve(10)

for i in range(1, 11):
    print(i, values[i])

Output:

1 1
2 1
3 2
4 2
5 4
6 2
7 6
8 4
9 6
10 4

Complexity:

O(n log log n)

This is useful for batch computations.

Linear Sieve for Phi

A linear sieve can compute phi values in O(n).

def phi_linear_sieve(n):
    primes = []
    is_composite = [False] * (n + 1)
    phi = [0] * (n + 1)

    phi[1] = 1

    for x in range(2, n + 1):
        if not is_composite[x]:
            primes.append(x)
            phi[x] = x - 1

        for p in primes:
            if x * p > n:
                break

            is_composite[x * p] = True

            if x % p == 0:
                phi[x * p] = phi[x] * p
                break

            phi[x * p] = phi[x] * (p - 1)

    return phi

This version is more complex but useful when computing several multiplicative functions together.

Application: Counting Reduced Fractions

The number of reduced fractions:

a/n

with:

1 ≤ a ≤ n

equals:

φ(n)

because the fraction is reduced exactly when:

gcd(a,n) = 1

For example, with denominator 10, the reduced fractions are:

1/10
3/10
7/10
9/10

There are:

φ(10) = 4

Application: RSA

RSA relies directly on phi.

Given:

n = pq

where p and q are distinct primes:

φ(n) = (p-1)(q-1)

The private exponent d is chosen so that:

ed ≡ 1 (mod φ(n))

This is why factoring n breaks RSA: once p and q are known, φ(n) becomes easy to compute.

Common Mistakes

Confusing φ(n) with Number of Divisors

φ(n) counts coprime residues. It does not count divisors.

For example:

φ(12) = 4

but 12 has six positive divisors:

1 2 3 4 6 12

Forgetting Distinct Prime Factors Only

In the formula:

φ(n) = n × Π(1 - 1/p)

each prime factor appears once.

For:

72 = 2³ × 3²

use 2 and 3, not repeated copies.

Using Floating-Point Arithmetic

Keep the computation integer-only.

Use:

result -= result // p

Assuming Multiplicativity Without Coprimality

The identity:

φ(ab) = φ(a)φ(b)

requires:

gcd(a,b) = 1

It does not hold in general.

Testing

Basic tests:

def test_phi():
    assert phi(1) == 1
    assert phi(2) == 1
    assert phi(5) == 4
    assert phi(8) == 4
    assert phi(9) == 6
    assert phi(10) == 4
    assert phi(36) == 12

Cross-check against the naive version for small inputs:

def test_phi_against_naive():
    for n in range(1, 200):
        assert phi(n) == phi_naive(n)

The naive implementation is slow, but it is excellent as a correctness oracle for small values.

Takeaway

Euler's phi function counts the integers up to n that are coprime to n. Its efficient computation depends on the distinct prime factors of n, using the formula φ(n) = n Π(1 - 1/p). Phi is multiplicative over coprime inputs, governs Euler's theorem, and supports modular inverses, RSA, reduced-fraction counting, and many multiplicative-function algorithms. For repeated queries, sieve-based methods compute phi values for all integers in a range efficiently.