2019-01-28 22:59:13 +01:00
|
|
|
|
{
|
|
|
|
|
"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,
|
2019-01-30 05:18:05 +01:00
|
|
|
|
"metadata": {
|
|
|
|
|
"collapsed": true
|
|
|
|
|
},
|
2019-01-28 22:59:13 +01:00
|
|
|
|
"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,
|
2019-01-30 05:18:05 +01:00
|
|
|
|
"metadata": {
|
|
|
|
|
"collapsed": true
|
|
|
|
|
},
|
2019-01-28 22:59:13 +01:00
|
|
|
|
"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": {
|
2019-01-30 05:18:05 +01:00
|
|
|
|
"completion_date": "Mon, 28 Jan 2019, 21:08",
|
2019-01-28 22:59:13 +01:00
|
|
|
|
"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": [
|
2019-01-30 05:18:05 +01:00
|
|
|
|
"diophantine",
|
|
|
|
|
"equation",
|
|
|
|
|
"pell's equation"
|
2019-01-28 22:59:13 +01:00
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"nbformat": 4,
|
|
|
|
|
"nbformat_minor": 2
|
|
|
|
|
}
|