Project Euler 134 – Investigating consecutive primes and the Extended Euclidean Algorithm

by Rob on January 22, 2012

in Code Samples,Project Euler,programming

http://projecteuler.net/problem=134

My code took 2.5 seconds. In order to optimize this code, I had to use the Extended Euclidean Algorithm that I read about in Wikipedia. Brute force won’t work, so this optimization speeds up the code substantially. In essence, you are solving for a linear congruence of the form ax = b mod n.

#euler 134

# generate prime list
import time
t0 = time.time()
import math

def sieve(n):
    initSieve = []
    maxNum = int(math.sqrt(n))+1
    for i in range(2,n):
        initSieve.append(True)
    j = 2
    while j <= maxNum:
        if initSieve[j-2]:
            for k in range(j*j, n, j):
                initSieve[k-2] = False
        j += 1
    outputList = [x+2 for x in range(len(initSieve)) if initSieve[x]]
    return outputList

factors = sieve(1000000)

#factors[2] is 5
# we actually need the next prime number greater than 1000000 in our list
def isprime(n):
    n*=1.0
    if n%2==0 and n!=2 or n%3==0 and n!=3:
        return False
    for b in range(1,int((n**0.5+1)/6.0+1)):
        if n%(6*b-1)==0:
            return False
        if n %(6*b+1)==0:
           return False
    return True

extraP = 1000000
while not isprime(extraP):
    extraP += 1
factors.append(extraP)

def pr(index):  # takes index
    p1 = factors[index]
    p2 = factors[index+1]
    return p1, p2

# use extended euclidean algorithm (from Wikipedia)

def exgcd(a,b):
    x = 0
    lastx = 1
    y = 1
    lasty = 0
    while b != 0:
        quotient = a/b
        a, b = b, a%b
        x, lastx = lastx - quotient*x, x
        y, lasty = lasty - quotient *y, y
    return lastx, lasty, a

# pr function will return two number p1, p2 based on index of prime sieve
# i.e. pr(7) returns 19, 23
# we want the second number, p2, to be the base for our modulus (i.e mod 23)
# we want to solve equation of the form
# 100 * x + 19 is congruent to 0 mod 23
# which is 100 * x is congruent to 4 mod 23
# the 100 is based on the length of p1, i.e. if p1 is 2 digits, then take 10^2
# The solution of the linear congruence: ax is congruent to b mod n
# is x = rb/d where
# r is returned by our extended euclidean algorithm
# ra + sn =d (our function exgcd of a, b returns lastx, lasty, a and
# in this case r is last x
# d is the gcd, and since we are always looking at 2 primes, this is always 1

def solvelc(p1, p2):  #takes as input 2 consecutive primes
    length = len(str(p1))
    a = int(math.pow(10, length))
    b = p2-p1
    n = p2
    r, s, d = exgcd(a,n)
    x = r*b
    x = x % n  # take modulus to find lowest x in congruent set
    return x*a + p1

answer = 0
for i in range(2, len(factors)-1):
    p1, p2 = pr(i)
    temp = solvelc(p1,p2)
    answer += temp
##    print p1, p2, temp, answer

print answer

t1 = time.time()
print t1-t0, "seconds"

Leave a Comment

Previous post:

Next post: