diff --git a/ipython/EulerProblem066.ipynb b/ipython/EulerProblem066.ipynb new file mode 100644 index 0000000..a761e06 --- /dev/null +++ b/ipython/EulerProblem066.ipynb @@ -0,0 +1,276 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Diophantine equation (Euler Problem 66)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "Consider quadratic Diophantine equations of the form:\n", + "\n", + "$x^2 – Dy^2 = 1$\n", + "\n", + "For example, when D=13, the minimal solution in x is 6492 – 13×1802 = 1.\n", + "\n", + "It can be assumed that there are no solutions in positive integers when D is square.\n", + "\n", + "By finding minimal solutions in x for D = {2, 3, 5, 6, 7}, we obtain the following:\n", + "\n", + "$3^2 – 2×2^2 = 1$\n", + "\n", + "$2^2 – 3×1^2 = 1$\n", + "\n", + "$9^2 – 5×4^2 = 1$\n", + "\n", + "$5^2 – 6×2^2 = 1$\n", + "\n", + "$8^2 – 7×3^2 = 1$\n", + "\n", + "Hence, by considering minimal solutions in x for D ≤ 7, the largest x is obtained when D=5.\n", + "\n", + "Find the value of D ≤ 1000 in minimal solutions of x for which the largest value of x is obtained.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import math\n", + "\n", + "def get_floor_sqrt(n):\n", + " return math.floor(math.sqrt(n))\n", + "\n", + "assert(get_floor_sqrt(5) == 2)\n", + "assert(get_floor_sqrt(23) == 4)\n", + "\n", + "def next_expansion_1(current_a, current_nominator, current_denominator, original_number):\n", + " cn = current_nominator\n", + " cd = current_denominator\n", + " cn, cd = cd, (original_number - cd * cd) // cn\n", + " next_a = math.floor((math.sqrt(original_number) + cn) // cd)\n", + " cn = cn - next_a * cd\n", + " cn *= -1\n", + " \n", + " return next_a, cn, cd\n", + "\n", + "def get_continued_fraction_sequence(n):\n", + " \n", + " # If number is a square number we return it.\n", + " floor_sqrt = get_floor_sqrt(n)\n", + " if n == floor_sqrt * floor_sqrt:\n", + " return ((floor_sqrt), [])\n", + " \n", + " # Otherwise, we calculate the next expansion till we\n", + " # encounter a step a second time. \n", + " a = floor_sqrt\n", + " cn = a\n", + " cd = 1\n", + " sequence = []\n", + " previous_steps = []\n", + " \n", + " while not (a, cn, cd) in previous_steps :\n", + " #print(\"a: {} cn: {} cd: {}\".format(a, cn, cd))\n", + " previous_steps.append((a, cn, cd))\n", + " a, cn, cd = next_expansion_1(a, cd, cn, n)\n", + " sequence.append(a)\n", + " sequence.pop()\n", + " return ((floor_sqrt), sequence)\n", + "\n", + "def get_continued_fraction_sequence(n):\n", + " \n", + " # If number is a square number we return it.\n", + " floor_sqrt = get_floor_sqrt(n)\n", + " if n == floor_sqrt * floor_sqrt:\n", + " return ((floor_sqrt), [])\n", + " \n", + " # Otherwise, we calculate the next expansion till we\n", + " # encounter a step a second time. \n", + " a = floor_sqrt\n", + " cn = a\n", + " cd = 1\n", + " sequence = []\n", + " previous_steps = []\n", + " \n", + " while not (a, cn, cd) in previous_steps :\n", + " #print(\"a: {} cn: {} cd: {}\".format(a, cn, cd))\n", + " previous_steps.append((a, cn, cd))\n", + " a, cn, cd = next_expansion_1(a, cd, cn, n)\n", + " sequence.append(a)\n", + " sequence.pop()\n", + " return ((floor_sqrt), sequence)\n", + "\n", + "assert(get_continued_fraction_sequence(1) == ((1), []))\n", + "assert(get_continued_fraction_sequence(4) == ((2), []))\n", + "assert(get_continued_fraction_sequence(25) == ((5), []))\n", + "assert(get_continued_fraction_sequence(2) == ((1), [2]))\n", + "assert(get_continued_fraction_sequence(3) == ((1), [1,2]))\n", + "assert(get_continued_fraction_sequence(5) == ((2), [4]))\n", + "assert(get_continued_fraction_sequence(13) == ((3), [1,1,1,1,6]))" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "def gcd(a, b):\n", + " if b > a:\n", + " a, b = b, a\n", + " while a % b != 0:\n", + " a, b = b, a % b\n", + " return b\n", + "\n", + "def add_fractions(n1, d1, n2, d2):\n", + " d = d1 * d2\n", + " n1 = n1 * (d // d1)\n", + " n2 = n2 * (d // d2)\n", + " n = n1 + n2\n", + " p = gcd(n, d)\n", + " return (n // p, d // p)\n", + "\n", + "def next_expansion_2(previous_numerator, previous_denumerator, value):\n", + " if previous_numerator == 0:\n", + " return (value, 1)\n", + " return add_fractions(previous_denumerator, previous_numerator, value, 1)\n", + " \n", + "def get_fractions(n, x):\n", + " #print(\"get_fractions(n={}, x={})\".format(n, x))\n", + " # Get sequence of a_x\n", + " first_value, sequence = get_continued_fraction_sequence(n)\n", + " sequence = [first_value] + math.ceil(x / len(sequence)) * sequence\n", + " sequence = sequence[:x + 1]\n", + " sequence = sequence[::-1]\n", + " \n", + " n, d = 0, 1\n", + " for s in sequence:\n", + " n, d = next_expansion_2(n, d, s)\n", + " return (n, d)\n", + "\n", + "assert(get_fractions(7, 0) == (2, 1))\n", + "assert(get_fractions(7, 1) == (3, 1))\n", + "assert(get_fractions(7, 2) == (5, 2))\n", + "assert(get_fractions(7, 3) == (8, 3))" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "def get_minimal_solution(d):\n", + " for i in range(0, 100):\n", + " x, y = get_fractions(d, i)\n", + " if x * x - d * y * y == 1:\n", + " return((x, y))\n", + "\n", + "assert(get_minimal_solution(2) == (3, 2))\n", + "assert(get_minimal_solution(3) == (2, 1))\n", + "assert(get_minimal_solution(85) == (285769, 30996))\n", + "assert(get_minimal_solution(109) == (158070671986249, 15140424455100))" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "from math import sqrt\n", + "\n", + "def is_square(n):\n", + " return sqrt(n).is_integer()\n", + "\n", + "print(is_square(4))" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "d: 661 x: 16421658242965910275055840472270471049\n" + ] + } + ], + "source": [ + "x_max = 0\n", + "d_max = 0\n", + "\n", + "for d in range(2, 1001):\n", + " if is_square(d):\n", + " continue\n", + " \n", + " x, y = get_minimal_solution(d)\n", + " if x > x_max:\n", + " x_max = x\n", + " d_max = d\n", + "\n", + "print(\"d: {} x: {}\".format(d_max, x_max))\n", + "s = d_max\n", + "assert(s == 661)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "completion_date": "Tue, 22 Jan 2019, 05:10", + "kernelspec": { + "display_name": "Python 3", + "language": "python3.6", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + }, + "tags": [ + "fractions", + "square roots", + "sequence", + "periodic" + ] + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/ipython/html/EulerProblem066.html b/ipython/html/EulerProblem066.html new file mode 100644 index 0000000..0262e23 --- /dev/null +++ b/ipython/html/EulerProblem066.html @@ -0,0 +1,12021 @@ + + + + +EulerProblem066 + + + + + + + + + + + + + + +
+
+
+
+
+
+

Diophantine equation (Euler Problem 66)

Back to overview.

+
+
+
+
+
+
+
+

Consider quadratic Diophantine equations of the form:

+

$x^2 – Dy^2 = 1$

+

For example, when D=13, the minimal solution in x is 6492 – 13×1802 = 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.

+
+
+
+
+
+
In [1]:
+
+
+
import math
+
+def get_floor_sqrt(n):
+    return math.floor(math.sqrt(n))
+
+assert(get_floor_sqrt(5) == 2)
+assert(get_floor_sqrt(23) == 4)
+
+def next_expansion_1(current_a, current_nominator, current_denominator, original_number):
+    cn = current_nominator
+    cd = current_denominator
+    cn, cd = cd, (original_number - cd * cd) // cn
+    next_a = math.floor((math.sqrt(original_number) + cn) // cd)
+    cn = cn - next_a * cd
+    cn *= -1
+    
+    return next_a, cn, cd
+
+def get_continued_fraction_sequence(n):
+    
+    # If number is a square number we return it.
+    floor_sqrt = get_floor_sqrt(n)
+    if n == floor_sqrt * floor_sqrt:
+        return ((floor_sqrt), [])
+    
+    # Otherwise, we calculate the next expansion till we
+    # encounter a step a second time.    
+    a = floor_sqrt
+    cn = a
+    cd = 1
+    sequence = []
+    previous_steps = []
+    
+    while not (a, cn, cd) in previous_steps :
+        #print("a: {} cn: {} cd: {}".format(a, cn, cd))
+        previous_steps.append((a, cn, cd))
+        a, cn, cd = next_expansion_1(a, cd, cn, n)
+        sequence.append(a)
+    sequence.pop()
+    return ((floor_sqrt), sequence)
+
+def get_continued_fraction_sequence(n):
+    
+    # If number is a square number we return it.
+    floor_sqrt = get_floor_sqrt(n)
+    if n == floor_sqrt * floor_sqrt:
+        return ((floor_sqrt), [])
+    
+    # Otherwise, we calculate the next expansion till we
+    # encounter a step a second time.    
+    a = floor_sqrt
+    cn = a
+    cd = 1
+    sequence = []
+    previous_steps = []
+    
+    while not (a, cn, cd) in previous_steps :
+        #print("a: {} cn: {} cd: {}".format(a, cn, cd))
+        previous_steps.append((a, cn, cd))
+        a, cn, cd = next_expansion_1(a, cd, cn, n)
+        sequence.append(a)
+    sequence.pop()
+    return ((floor_sqrt), sequence)
+
+assert(get_continued_fraction_sequence(1) == ((1), []))
+assert(get_continued_fraction_sequence(4) == ((2), []))
+assert(get_continued_fraction_sequence(25) == ((5), []))
+assert(get_continued_fraction_sequence(2) == ((1), [2]))
+assert(get_continued_fraction_sequence(3) == ((1), [1,2]))
+assert(get_continued_fraction_sequence(5) == ((2), [4]))
+assert(get_continued_fraction_sequence(13) == ((3), [1,1,1,1,6]))
+
+
+
+
+
+
+
+
In [43]:
+
+
+
def gcd(a, b):
+    if b > a:
+        a, b = b, a
+    while a % b != 0:
+        a, b = b, a % b
+    return b
+
+def add_fractions(n1, d1, n2, d2):
+    d = d1 * d2
+    n1 = n1 * (d // d1)
+    n2 = n2 * (d // d2)
+    n = n1 + n2
+    p = gcd(n, d)
+    return (n // p, d // p)
+
+def next_expansion_2(previous_numerator, previous_denumerator, value):
+    if previous_numerator == 0:
+        return (value, 1)
+    return add_fractions(previous_denumerator, previous_numerator, value, 1)
+    
+def get_fractions(n, x):
+    #print("get_fractions(n={}, x={})".format(n, x))
+    # Get sequence of a_x
+    first_value, sequence = get_continued_fraction_sequence(n)
+    sequence = [first_value] + math.ceil(x / len(sequence)) * sequence
+    sequence = sequence[:x + 1]
+    sequence = sequence[::-1]
+    
+    n, d = 0, 1
+    for s in sequence:
+        n, d = next_expansion_2(n, d, s)
+    return (n, d)
+
+assert(get_fractions(7, 0) == (2, 1))
+assert(get_fractions(7, 1) == (3, 1))
+assert(get_fractions(7, 2) == (5, 2))
+assert(get_fractions(7, 3) == (8, 3))
+
+
+
+
+
+
+
+
In [48]:
+
+
+
def get_minimal_solution(d):
+    for i in range(0, 100):
+        x, y = get_fractions(d, i)
+        if x * x - d * y * y == 1:
+            return((x, y))
+
+assert(get_minimal_solution(2) == (3, 2))
+assert(get_minimal_solution(3) == (2, 1))
+assert(get_minimal_solution(85) == (285769, 30996))
+assert(get_minimal_solution(109) == (158070671986249, 15140424455100))
+
+
+
+
+
+
+
+
In [52]:
+
+
+
from math import sqrt
+
+def is_square(n):
+    return sqrt(n).is_integer()
+
+print(is_square(4))
+
+
+
+
+
+
+
+
+
+
True
+
+
+
+
+
+
+
+
+
In [55]:
+
+
+
x_max = 0
+d_max = 0
+
+for d in range(2, 1001):
+    if is_square(d):
+        continue
+    
+    x, y = get_minimal_solution(d)
+    if x > x_max:
+        x_max = x
+        d_max = d
+
+print("d: {} x: {}".format(d_max, x_max))
+s = d_max
+assert(s == 661)
+
+
+
+
+
+
+
+
+
+
d: 661 x: 16421658242965910275055840472270471049
+
+
+
+
+
+
+
+
+
In [ ]:
+
+
+
 
+
+
+
+
+
+
+
+ + diff --git a/ipython/html/index.html b/ipython/html/index.html index 4610f05..077d06d 100644 --- a/ipython/html/index.html +++ b/ipython/html/index.html @@ -1039,6 +1039,24 @@ + + + Problem 066 + Tue, 22 Jan 2019, 05:10 + + + fractions + + square roots + + sequence + + periodic + + + + + Problem 067