euler/ipython/EulerProblem066.ipynb

280 lines
7.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"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": {
"collapsed": true
},
"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": {
"collapsed": true
},
"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": "Mon, 28 Jan 2019, 21:08",
"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": [
"diophantine",
"equation",
"pell's equation"
]
},
"nbformat": 4,
"nbformat_minor": 2
}