Is there a fast algorithm for Euler's totient function of BIG numbers (128bit)?

Viewed 3637

I need to get phi-function (Euler's) of some randomly generated 128-bit numbers. I tried to use this code below but computer is just thinking too much.

import fractions

def phi(n):
    amount = 0        
    for k in range(1, n + 1):
        if fractions.gcd(n, k) == 1:
            amount += 1
    return amount

Is there something faster?

1 Answers

For 128-bit numbers, you're going to want to efficiently compute the prime factorization of n, then use

totient = n
for factor in prime_factors(n):
    totient -= totient // factor

The hard part is the factorization. For 128-bit numbers, simple trial division is going to be horribly inefficient. Something like elliptic curve factorization or a quadratic sieve would be better, but writing those by hand is hard. It's probably better to use a library.

The best Python implementation of a large-number factorization algorithm I've found is, believe it or not, this answer by primo on codegolf.stackexchange.com. It's a multiple-polynomial quadratic sieve.

primefac (Python 2) and labmath (Python 3) incorporate a quadratic sieve, but it's based on an old, somewhat slow and buggy version of the Code Golf answer. If you want the fixed version, you'll want to go to the Code Golf answer. (Also, be aware that labmath.factorint defaults to not using the mpqs implementation.) labmath and primefac also include elliptic curve factorization, and a few other algorithms that are less likely to be useful for this input size.

Aside from that, there's sympy.ntheory.factorint, but it had problems with large factors in my tests, and it only has trial division, pollard rho, and pollard p-1 factorization.


Anyway, use one of those existing factorization options, or implement your own, or whatever, and then build your totient function on top of that. For example, using primefac:

# primefac.factorint(n) returns a factor:multiplicity dict
from primefac import factorint

def totient(n):
    totient = n
    for factor in factorint(n):
        totient -= totient // factor
    return totient
Related