https://www.codewars.com/kata/number-of-proper-fractions-with-denominator-d/train/python

Task

If n is the numerator and d the denominator of a fraction, that fraction is defined a (reduced) proper fraction if and only if GCD(n,d)==1.

For example 5/16 is a proper fraction, while 6/16 is not, as both 6 and 16 are divisible by 2, thus the fraction can be reduced to 3/8.

Now, if you consider a given number d, how many proper fractions can be built using d as a denominator?

For example, let's assume that d is 15: you can build a total of 8 different proper fractions between 0 and 1 with it: 1/15, 2/15, 4/15, 7/15, 8/15, 11/15, 13/15 and 14/15.

You are to build a function that computes how many proper fractions you can build with a given denominator:

proper_fractions(1)==0
proper_fractions(2)==1
proper_fractions(5)==4
proper_fractions(15)==8
proper_fractions(25)==20

Be ready to handle big numbers.

Edit: to be extra precise, the term should be "reduced" fractions, thanks to girianshiido for pointing this out and sorry for the use of an improper word :)

Best Practices

Py First:

def proper_fractions(n):
    phi = n > 1 and n
    for p in range(2, int(n ** .5) + 1):
        if not n % p:
            phi -= phi // p
            while not n % p:
                n //= p
    if n > 1: phi -= phi // n
    return phi

Py Second:

def euler(n):
    res = 1.0*n
    p = 2
    while p*p <= n:
        if n%p == 0:
            while n%p == 0:
                n = n/p
            res *= (1.0 - (1.0/p) )
        p += 1

    if n > 1:
        res *= (1.0 - (1.0/n) )

    return int(res)

def proper_fractions(d):
    if d == 1:
        return 0
    return euler(d)

Py Third:

primes=[2,3,5,7,11,13,17,19,23,29,31]

def is_prime(n):
    limit=int(n**.5)+1
    for div in primes:
        if div>limit: break
        if n%div==0: return False
    return True

def expand_primes(n):
    global primes
    for i in range(primes[-1]/6*6,n+6,6):
        if is_prime(i-1) and (i-1)>primes[-1]: primes+=[i-1]
        if is_prime(i+1) and (i+1)>primes[-1]: primes+=[i+1]

def divisors(n):
    res,orig=[],n
    for prime in primes:
        if prime**2>n: break
        if n%prime==0:
            res+=[prime]
            while n%prime==0: n/=prime
        if prime==primes[-1] and n>prime**2: expand_primes(int(n**.5)+1)
    return res if n==1 else res+[n]

def proper_fractions(n):
    if n<2: return 0
    for div in divisors(n):
        n=n/div*(div-1)
    return n

results matching ""

    No results matching ""