Project Euler Problem 72 Solution

Question

Consider the fraction, \frac{n}{d}, where n and d are positive integers. If n \lt d and \mathrm{HCF}(n,d)=1, it is called a reduced proper fraction.

If we list the set of reduced proper fractions for d \leq 8 in ascending order of size, we get:

\frac{1}{8}, \frac{1}{7}, \frac{1}{6}, \frac{1}{5}, \frac{1}{4}, \frac{2}{7}, \frac{1}{3}, \frac{3}{8}, \frac{2}{5}, \frac{3}{7}, \frac{1}{2}, \frac{4}{7}, \frac{3}{5}, \frac{5}{8}, \frac{2}{3}, \frac{5}{7}, \frac{3}{4}, \frac{4}{5}, \frac{5}{6}, \frac{6}{7}, \frac{7}{8}

It can be seen that there are 21 elements in this set.

How many elements would be contained in the set of reduced proper fractions for d \leq 1,000,000?

Haskell

farey :: Int -> Int
farey = (map f [0..] !!) where
    f n = (n*(n + 3)) `quot` 2 - sum [farey (n `quot` k) | k <- [2..n]]

main :: IO ()
main = print $ farey 1000000 - farey 1
$ ghc -O2 -o counting-fractions counting-fractions.hs
$ time ./counting-fractions
real   0m0.372s
user   0m0.364s
sys    0m0.008s

Python

#!/usr/bin/env python
import math
from operator import mul
from functools import reduce

def prime_factors(n):
    res = set()
    # iterate over all even numbers first.
    while n % 2 == 0:
        res.add(2)
        n //= 2
    # try odd numbers up to sqrt(n)
    limit = math.sqrt(n+1)
    i = 3
    while i <= limit:
        if n % i == 0:
            res.add(i)
            n //= i
            limit = math.sqrt(n+i)
        else:
            i += 2
    if n != 1:
        res.add(n)
    return res

def totient(n):
    if n == 1: return 1
    return int(round(n * reduce(mul, [1 - 1.0 / p for p in prime_factors(n)])))

def farey_length(n):
    return sum(totient(m) for m in range(1, n+1)) - 1

def main():
    print(farey_length(1000000))

if __name__ == "__main__": main()
$ time python3 farey.py
real   0m13.880s
user   0m13.879s
sys    0m0.000s