# Euler Problem 003¶

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.