2019-07-18 20:23:44 +02:00
|
|
|
|
import math
|
|
|
|
|
from e057 import add_fractions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_floor_sqrt(n):
|
|
|
|
|
return math.floor(math.sqrt(n))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 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)
|
|
|
|
|
|
|
|
|
|
|
2019-08-12 03:42:31 +02:00
|
|
|
|
def get_minimal_solution_old(d):
|
2019-07-18 20:23:44 +02:00
|
|
|
|
for i in range(0, 100):
|
|
|
|
|
x, y = get_fractions(d, i)
|
|
|
|
|
if x * x - d * y * y == 1:
|
|
|
|
|
return((x, y))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_square(n):
|
|
|
|
|
return math.sqrt(n).is_integer()
|
|
|
|
|
|
2019-07-18 03:29:59 +02:00
|
|
|
|
|
2019-08-12 03:42:31 +02:00
|
|
|
|
def get_minimal_solution(d, d1=0, n1=1, d2=1, n2=1):
|
|
|
|
|
"""
|
|
|
|
|
This is an alternative to the alternate fraction approach explained here
|
|
|
|
|
[1]. Instead of calculating the continued fraction we search the
|
|
|
|
|
Stern-Brocot tree for fractions (x / y) that satisfy the pell equation.
|
|
|
|
|
|
|
|
|
|
If the solution does not satisfy the equation we can searh the respective
|
|
|
|
|
branch by calculating the mediant between the current fraction and one of
|
|
|
|
|
the previous fractions.
|
|
|
|
|
|
|
|
|
|
[1] https://en.wikipedia.org/wiki/Pell's_equation#Fundamental_solution_via_continued_fractions
|
|
|
|
|
[2] https://en.wikipedia.org/wiki/Stern–Brocot_tree
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
x = n1 + n2
|
|
|
|
|
y = d1 + d2
|
|
|
|
|
p = x * x - d * y * y
|
|
|
|
|
if p == 1:
|
|
|
|
|
return (x, y)
|
|
|
|
|
if p < 1:
|
|
|
|
|
return get_minimal_solution(d, d1, n1, y, x)
|
|
|
|
|
else:
|
|
|
|
|
return get_minimal_solution(d, y, x, d2, n2)
|
|
|
|
|
|
|
|
|
|
|
2019-07-18 03:29:59 +02:00
|
|
|
|
def euler_066():
|
2019-07-18 20:23:44 +02:00
|
|
|
|
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:
|
2019-08-12 03:42:31 +02:00
|
|
|
|
x_max, d_max = x, d
|
2019-07-18 20:23:44 +02:00
|
|
|
|
|
|
|
|
|
print("d: {} x: {}".format(d_max, x_max))
|
|
|
|
|
s = d_max
|
|
|
|
|
return s
|
2019-07-18 03:29:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
print("e066.py: " + str(euler_066()))
|
2019-07-18 20:23:44 +02:00
|
|
|
|
assert(euler_066() == 661)
|