Ternas pitagóricas con suma dada
Una terna pitagórica es una terna de números naturales (a,b,c) tal que a<b<c y a²+b²=c². Por ejemplo (3,4,5) es una terna pitagórica.
Definir la función
1 |
ternasPitagoricas :: Integer -> [(Integer,Integer,Integer)] |
tal que ternasPitagoricas x
es la lista de las ternas pitagóricas cuya suma es x
. Por ejemplo,
1 2 3 |
ternasPitagoricas 12 == [(3,4,5)] ternasPitagoricas 60 == [(10,24,26),(15,20,25)] ternasPitagoricas (10^6) == [(218750,360000,421250),(200000,375000,425000)] |
Soluciones
A continuación se muestran las soluciones en Haskell y las soluciones en Python.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
import Data.List (nub,sort) import Test.QuickCheck -- 1ª solución -- -- =========== ternasPitagoricas1 :: Integer -> [(Integer,Integer,Integer)] ternasPitagoricas1 x = [(a,b,c) | a <- [0..x], b <- [a+1..x], c <- [b+1..x], a^2 + b^2 == c^2, a+b+c == x] -- 2ª solución -- -- =========== ternasPitagoricas2 :: Integer -> [(Integer,Integer,Integer)] ternasPitagoricas2 x = [(a,b,c) | a <- [1..x], b <- [a+1..x-a], let c = x-a-b, a^2+b^2 == c^2] -- 3ª solución -- -- =========== -- Todas las ternas pitagóricas primitivas (a,b,c) pueden representarse -- por -- a = m^2 - n^2, b = 2*m*n, c = m^2 + n^2, -- con 1 <= n < m. (Ver en https://bit.ly/35UNY6L ). ternasPitagoricas3 :: Integer -> [(Integer,Integer,Integer)] ternasPitagoricas3 x = nub [(d*a,d*b,d*c) | d <- [1..x], x `mod` d == 0, (a,b,c) <- aux (x `div` d)] where aux y = [(a,b,c) | m <- [2..limite], n <- [1..m-1], let [a,b] = sort [m^2 - n^2, 2*m*n], let c = m^2 + n^2, a+b+c == y] where limite = ceiling (sqrt (fromIntegral y)) -- Equivalencia de las definiciones -- ================================ -- La propiedad es prop_ternasPitagoricas :: Positive Integer -> Bool prop_ternasPitagoricas (Positive x) = all (== (ternasPitagoricas1 x)) [ternasPitagoricas2 x, ternasPitagoricas3 x] -- La comprobación es -- λ> quickCheck prop_ternasPitagoricas -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> ternasPitagoricas1 200 -- [(40,75,85)] -- (1.90 secs, 2,404,800,856 bytes) -- λ> ternasPitagoricas2 200 -- [(40,75,85)] -- (0.06 secs, 19,334,232 bytes) -- λ> ternasPitagoricas3 200 -- [(40,75,85)] -- (0.01 secs, 994,224 bytes) -- -- λ> ternasPitagoricas2 3000 -- [(500,1200,1300),(600,1125,1275),(750,1000,1250)] -- (4.41 secs, 4,354,148,136 bytes) -- λ> ternasPitagoricas3 3000 -- [(500,1200,1300),(600,1125,1275),(750,1000,1250)] -- (0.05 secs, 17,110,360 bytes) |
El código se encuentra en GitHub.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
from math import ceil, sqrt from timeit import Timer, default_timer from hypothesis import given from hypothesis import strategies as st # 1ª solución -- # =========== def ternasPitagoricas1(x: int) -> list[tuple[int, int, int]]: return [(a, b, c) for a in range(0, x+1) for b in range(a+1, x+1) for c in range(b+1, x+1) if a**2 + b**2 == c**2 and a + b + c == x] # 2ª solución -- # =========== def ternasPitagoricas2(x: int) -> list[tuple[int, int, int]]: return [(a, b, c) for a in range(1, x+1) for b in range(a+1, x-a+1) for c in [x - a - b] if a**2 + b**2 == c**2] # 3ª solución -- # =========== # Todas las ternas pitagóricas primitivas (a,b,c) pueden representarse # por # a = m^2 - n^2, b = 2*m*n, c = m^2 + n^2, # con 1 <= n < m. (Ver en https://bit.ly/35UNY6L ). def ternasPitagoricas3(x: int) -> list[tuple[int, int, int]]: def aux(y: int) -> list[tuple[int, int, int]]: return [(a, b, c) for m in range(2, 1 + ceil(sqrt(y))) for n in range(1, m) for a in [min(m**2 - n**2, 2*m*n)] for b in [max(m**2 - n**2, 2*m*n)] for c in [m**2 + n**2] if a+b+c == y] return list(set(((d*a, d*b, d*c) for d in range(1, x+1) for (a, b, c) in aux(x // d) if x % d == 0))) # Comprobación de equivalencia # ============================ # La propiedad es @given(st.integers(min_value=1, max_value=50)) def test_ternasPitagoricas(n: int) -> None: r = set(ternasPitagoricas1(n)) assert set(ternasPitagoricas2(n)) == r assert set(ternasPitagoricas3(n)) == r # La comprobación es # src> poetry run pytest -q ternas_pitagoricas_con_suma_dada.py # 1 passed in 0.35s # Comparación de eficiencia # ========================= def tiempo(e: str) -> None: """Tiempo (en segundos) de evaluar la expresión e.""" t = Timer(e, "", default_timer, globals()).timeit(1) print(f"{t:0.2f} segundos") # La comparación es # >>> tiempo('ternasPitagoricas1(300)') # 2.83 segundos # >>> tiempo('ternasPitagoricas2(300)') # 0.01 segundos # >>> tiempo('ternasPitagoricas3(300)') # 0.00 segundos # # >>> tiempo('ternasPitagoricas2(3000)') # 1.48 segundos # >>> tiempo('ternasPitagoricas3(3000)') # 0.02 segundos |
El código se encuentra en GitHub.