# Euler Problem 003¶

Back to overview.

The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143?

We start by writing a function which calculates all primes till a certain value using the Sieve of Eratosthenes.

In [1]:

    def get_primes_smaller(number):
        primes = []
        prospects = [n for n in range(2, number)]
        while prospects:
            p = prospects[0]
            prospects = [x for x in prospects if x % p != 0]
            primes.append(p)
        return primes

    assert(get_primes_smaller(0) == [])
    assert(get_primes_smaller(10) == [2, 3, 5, 7,])

Now we create a function which does prime factorization. It is very important that we only test primes smaller than the squre root. Otherwise the complexity becomes too big.

In [2]:

    import math

    def get_prime_factors(number):
        possible_factors = get_primes_smaller(math.ceil(math.sqrt(number)))
        remainder = number
        factors = []
        for p in possible_factors:
            while remainder % p == 0:
                remainder /= p
                factors.append(p)
            if remainder == 1:
                break
        if remainder != 1:
            factors.append(remainder)
        return factors

    assert(get_prime_factors(7) == [7])
    assert(get_prime_factors(12) == [2, 2, 3])
    assert(get_prime_factors(88) == [2, 2, 2, 11])
    assert(get_prime_factors(13195) == [5, 7, 13, 29])

Now we can go ahead an brute force the solution.

In [3]:

    def get_largest_prime(number):
        return get_prime_factors(number)[-1]

    assert(get_largest_prime(13195) == 29)
    #print(get_largest_prime(600851475143))
    print(6857) # computed the previously but remove it so that we can reexecute the complete kernel

    6857

Okay, actually we can brute force, but it is really slow. A better solution is to write a prime number generator which calculates the next number on demand.

In [4]:

    def is_prime(n, smaller_primes):
        for s in smaller_primes:
            if n % s == 0:
                return False
            if s * s > n:
                return True
        return True

    def prime_generator_function():
        primes = [2, 3, 5, 7]
        for p in primes:
            yield p
        while True:
            p += 2
            if is_prime(p, primes):
                primes.append(p)
                yield p

    def get_prime_factors(number):
        prime_generator = prime_generator_function()
        remainder = number
        factors = []
        for p in prime_generator:
            while remainder % p == 0:
                remainder /= p
                factors.append(p)
            if remainder == 1 or p * p > number:
                break
        if remainder != 1:
            factors.append(remainder)
        return factors

    print(get_largest_prime(600851475143))

    6857

Here we go. Obviously much better than precalculation primes that we never need.