diff --git a/python/e075.py b/python/e075.py index 6c90cb3..6203a44 100644 --- a/python/e075.py +++ b/python/e075.py @@ -1,4 +1,5 @@ from math import sqrt +from lib_misc import gcd def proper_divisors(n): @@ -28,16 +29,6 @@ def triples_brute_force(b_max): return triples -def triples_euclids_formula(m, n): - """ Does not return all triples! """ - assert(m > n) - assert(n > 0) - a = m * m - n * n - b = 2 * m * n - c = m * m + n * n - return (a, b, c) - - def dicksons_method(r): triples = [] assert(r % 2 == 0) @@ -94,7 +85,7 @@ def dicksons_method_efficient(r): return perimeters -def euler_075(): +def euler_075_dicksons(): """ We are using Dickson's method to get all Pythagorean triples. The challenge is that this method requires finding the divisors for a @@ -130,6 +121,57 @@ def euler_075(): return one_integer_sided_right_triangle_count +def triples_euclids_formula(m, n): + """ + Generates only primitive triples. + https://en.wikipedia.org/wiki/Pythagorean_triple#Generating_a_triple + """ + assert(m > n) + assert(n > 0) + assert(gcd(m, n) == 1) + assert(m % 2 == 0 or n % 2 == 0) + a = m * m - n * n + b = 2 * m * n + c = m * m + n * n + if a < b: + return (a, b, c) + else: + return (b, a, c) + + +def euler_075(): + """ + The range for m was chosen empirically (aka by trial and error). + I tried terminating when L > L_max the first time, but there might + be combinations for m = m + 1 that yield lower L. I guess the right + criteria to return would be if L > L_max and n == 1. + This is good enough for now. I still like my other solution, but it + is so much slower because finding the divisors is so expensive. + """ + L = 0 + L_max = 1500000 + m = 1 + perimeter_counts = {} + for m in range(1, 1000): + for n in range(1, m): + try: + L = sum(triples_euclids_formula(m, n)) + L_k = L + while L_k <= L_max: + try: + perimeter_counts[L_k] += 1 + except KeyError: + perimeter_counts[L_k] = 1 + L_k += L + except AssertionError: + pass + one_integer_sided_right_triangle_count = 0 + for perimeter, count in perimeter_counts.items(): + if count == 1: + one_integer_sided_right_triangle_count += 1 + return one_integer_sided_right_triangle_count + + if __name__ == "__main__": print("e075.py: " + str(euler_075())) assert(euler_075() == 161667)