Skip to main content

Project Euler Problem 66 Solution with python

Diophantine equation

Consider quadratic Diophantine equations of the form:

$$ x^{2} – Dy^{2} = 1 $$

For example, when $D = 13$, the minimal solution in $ x $ is $ 649^{2} – 13 \times 180^{2} = 1 $

It can be assumed that there are no solutions in positive integers when $ D $ is square.

By finding minimal solutions in $ x $ for $ D = {2, 3, 5, 6, 7} $, we obtain the following:

$$ 3^{2} – 2×2^{2} = 1 $$ $$ 2^{2} – 3×1^{2} = 1 $$ $$ 9^{2} – 5×4^{2} = 1 $$ $$ 5^{2} – 6×2^{2} = 1 $$ $$ 8^{2} – 7×3^{2} = 1 $$

Hence, by considering minimal solutions in $ x $ for $ D ≤ 7 $, the largest $ x $ is obtained when $ D = 5 $.

Find the value of $ D ≤ 1000 $ in minimal solutions of $ x $ for which the largest value of $ x $ is obtained.

If you have already solved Problem 64 on Project euler, then assume that this one is an extension to Problem 64.

If you have not solved Problem 64, try solving that problem first. Of course I have written a post on that.

The solution is based on two approaches: Chakravala method(Page No:3) and Continued Fraction method(Page No: 18). And to find continued fractions I have used this source: Wikipedia - Methods of Computing square roots.

As there is a lot of stuff in the given sources, the screen grabs of the required stuff is as follows:

Theorem Statement to solve pell's equation using continued fractions
Theorem statement to solve pells equation
Bhaskara Lemma to solve negative pells equation
Bhaskara's Lemma to solve negative pell's equation
Algorithm to find the continued fractions of a square root
Algorithm to find the continued fractions for square root of a number

There are four things that we will have to understand from the sources:

  1. If the period of the continued fraction is even then we are finding the solution for the positive pells equation - $ x^{2} - Dy^{2} = 1 $
  2. If the period of the continued fraction is odd then we are finding the solution for the negative pells equation - $ x^{2} - Dy^{2} = -1 $
  3. What ever might be the case, we don't need the last value of the convergent list. i.e. in our case $ \sqrt{19} = [4;2,1,3,1,2] $ instead of $ [4;2,1,3,1,2,8] $
  4. If we are solving the negative pells equation, then we will use Baskara's Lemma to get the required answer.

Now that you have understood the important points, have a look at the program and you are good to go.

Program

In [ ]:
# http://radiusofcircle.blogspot.com

#import time
import time

# square root function
from math import sqrt

# time at the start of program execution
start = time.time()

# function to calculate the continued fraction
def cf(n):
    mn = 0.0
    dn = 1.0
    a0 = int(sqrt(n))
    an = int(sqrt(n))
    convergents = [a0]
    period = 0
    if a0 != sqrt(n):
        while an != 2*a0:
            mn = dn*an - mn
            dn = (n - mn**2)/dn
            an = int((a0 + mn)/dn)
            convergents.append(an)
    return convergents[:-1]

def cf_inv(cf):
    """
    function to calculate the
    simple fraction from the continued
    fraction.
    """
    numerator = 1
    denominator = cf.pop()
    while cf:
        denominator, numerator = denominator*cf.pop() + numerator, denominator
    return denominator, numerator

# variable to store the largest value 
# and the place it occurs
largest = 0, 0

# for loop less than 1000
for i in xrange(1, 1001):
    if i%sqrt(i) != 0:
        continued_fraction = cf(i)
        if len(continued_fraction) % 2 != 0:
            u, v = cf_inv(continued_fraction)
            u, v = 2*u**2+1, 2*u*v
        else:
            u, v = cf_inv(continued_fraction)
        if u > largest[1]:
            largest = i, u

# print the largest value
print largest[0]

# time at the end of program execution
end = time.time()

# total time taken to run the program
print end - start

I have tried to name the variables as meaningful as possible. But a brief explanation is as follows:

The function cf will take a number($ n $) as input and calculate the continued fraction for square root of the number($ \sqrt{n} $).

So the expected output will be [a0, a1, a2, a3, .........., an]. Also from the reference, we know that an = 2a0. We also know that, to solve pell's equation we don't need the last value(an) and so cf will return a list with values excluding the last number.

The function cf_inv will take a list(List of continued fraction values) as input and will return the numerator and the denominator if the list is written as a simple fraction.

For example, consider the list: [2, 3, 4, 5]. This list when written as a continued fraction will be as follows: \begin{equation} x = 2 + \cfrac{1}{3 + \cfrac{1}{4 + \cfrac{1}{5} } } \\ \implies x = 2 + \cfrac{1}{3 + \cfrac{5}{21} } \\ \implies x = 2 + \cfrac{21}{68} \\ \implies x = \cfrac{157}{68} \end{equation} Now that you have understood how the function works in the background, we will use tweak the function so that it will print the numerator and denominator for each and every iteration.

In [1]:
def cf_inv(cf):
    numerator = 1
    denominator = cf.pop()
    while cf:
        denominator, numerator = denominator*cf.pop() + numerator, denominator
        print numerator, denominator
    return denominator, numerator

print cf_inv([2, 3, 4, 5])
5 21
21 68
68 157
(157, 68)

It should be noted that, when using the while loop, during the last iteration we will swap the numerator and denominator(Think why I am doing that and comment in the comment box below).

Rest of the code is simple and easy to understand, just a for loop to find the answer.

Output

Summary

When I started solving this problem, I started reading papers and articles on chakravala method and tried implementing the same. But for a few numbers I always got a wrong answer. I didn't knew why! After a few trial and errors I again started searching on the web, but this time "Solving Pell's equation" and finally found perfect source to solve the question. Further discussing about the problem, it was not really easy and I personally liked the problem. Still there is a room for improvement. But for now I am satisfied with the speed of execution.

If you have any doubts(not just related to this problem but any general ones are also welcome) or didn't understand anything comment in the comment box below and I will be glad to help you. Please comment in the comment box below if you have found any typo or have a better program.

You can also contact me.

Thank you. Have a nice day😃.

Popular posts from this blog

Making a quiz web app with python and flask

Edit : When you are creating a web app with h tml templates, then y ou will have to sa ve the html file in templates folder in the Current Wor ki ng Directory( CWD). If you save the file in the C W D directl y you will get a TemplateNotFound error. Thank you Udhay for pointing it out.   In this post we will create a quiz website using python . I will be using the flask framework . After reading this tutorial you will learn form submission , flask templates , python code in flask templates , shuffling the questions and options with the random module and few others.  Please note that this tutorial is not big as it seems to be. Some of the code has been rewritten to maintain consistency and also font size is somewhat big so that your eyes won't get stressed reading this tutorial. Also the content has not occupied the full width of the page. In this tutorial I am assuming that you are having a very basic understanding of the flask framework . Please refer the documentation

Problem 11 Project Euler Solution with python

Largest product in a grid In the 20×20 grid below, four numbers along a diagonal line have been marked in red. 08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65 52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91 22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80 24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50 32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70 67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21 24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72 21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95 78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92 16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57 86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58 19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40 04 52 08 83 97 35 99 16 07

Problem 60 Project Euler Solution with python

Prime pair sets The primes 3, 7, 109, and 673, are quite remarkable. By taking any two primes and concatenating them in any order the result will always be prime. For example, taking 7 and 109, both 7109 and 1097 are prime. The sum of these four primes, 792, represents the lowest sum for a set of four primes with this property. Find the lowest sum for a set of five primes for which any two primes concatenate to produce another prime. This problem is j u st a brute force problem. If you have come here because you don't know the limit upto which you will h ave to gener ate the prime numbers t hen go ahe ad and t r y with 10,000 . When I first start ed solving the problem I chose 1 million(beca use most of the problem s on project E uler have this limit ), but it took very long for the computer to fin d the solution. After searching on the internet then I found many people choosing 10, 000 so I have changed my in put f rom 1 million to 10000 and the output was f ast. He