Ir al contenido principal

Ternas pitagórica

Una terna (x,y,z) de enteros positivos es pitagórica si x² + y² = z² y x < y < z.

Definir la función

   pitagoricas :: Int -> [(Int,Int,Int)]

tal que pitagoricas n es la lista de todas las ternas pitagóricas cuyas componentes están entre 1 y n. Por ejemplo,

   pitagoricas 10  ==  [(3,4,5),(6,8,10)]
   pitagoricas 15  ==  [(3,4,5),(5,12,13),(6,8,10),(9,12,15)]

Soluciones

A continuación se muestran las soluciones en Haskell y las soluciones en Python.

Soluciones en Haskell

import Test.QuickCheck

-- 1ª solución
-- ===========

pitagoricas1 :: Int -> [(Int,Int,Int)]
pitagoricas1 n = [(x,y,z) | x <- [1..n]
                          , y <- [1..n]
                          , z <- [1..n]
                          , x^2 + y^2 == z^2
                          , x < y && y < z]

-- 2ª solución
-- ===========

pitagoricas2 :: Int -> [(Int,Int,Int)]
pitagoricas2 n = [(x,y,z) | x <- [1..n]
                          , y <- [x+1..n]
                          , z <- [ceiling (sqrt (fromIntegral (x^2+y^2)))..n]
                          , x^2 + y^2 == z^2]

-- 3ª solución
-- ===========

pitagoricas3 :: Int -> [(Int,Int,Int)]
pitagoricas3 n = [(x,y,z) | x <- [1..n]
                          , y <- [x+1..n]
                          , let z = round (sqrt (fromIntegral (x^2+y^2)))
                          , y < z
                          , z <= n
                          , x^2 + y^2 == z^2]

-- Comprobación de equivalencia
-- ============================

-- La propiedad es
prop_pitagoricas :: Positive Int -> Bool
prop_pitagoricas (Positive n) =
  all (== pitagoricas1 n)
      [pitagoricas2 n,
       pitagoricas3 n]

-- La comprobación es
--    λ> quickCheck prop_pitagoricas
--    +++ OK, passed 100 tests.

-- Comparación de eficiencia
-- =========================

-- La comparación es
--    λ> length (pitagoricas1 200)
--    127
--    (12.25 secs, 12,680,320,400 bytes)
--    λ> length (pitagoricas2 200)
--    127
--    (1.61 secs, 1,679,376,824 bytes)
--    λ> length (pitagoricas3 200)
--    127
--    (0.06 secs, 55,837,072 bytes)

El código se encuentra en GitHub.

Soluciones en Python

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 pitagoricas1(n: int) -> list[tuple[int, int, int]]:
    return [(x, y, z)
            for x in range(1, n+1)
            for y in range(1, n+1)
            for z in range(1, n+1)
            if x**2 + y**2 == z**2 and x < y < z]

# 2ª solución
# ===========

def pitagoricas2(n: int) -> list[tuple[int, int, int]]:
    return [(x, y, z)
            for x in range(1, n+1)
            for y in range(x+1, n+1)
            for z in range(ceil(sqrt(x**2+y**2)), n+1)
            if x**2 + y**2 == z**2]

# 3ª solución
# ===========

def pitagoricas3(n: int) -> list[tuple[int, int, int]]:
    return [(x, y, z)
            for x in range(1, n+1)
            for y in range(x+1, n+1)
            for z in [ceil(sqrt(x**2+y**2))]
            if y < z <= n and x**2 + y**2 == z**2]

# Comprobación de equivalencia
# ============================

# La propiedad es
@given(st.integers(min_value=1, max_value=50))
def test_pitagoricas(n: int) -> None:
    r = pitagoricas1(n)
    assert pitagoricas2(n) == r
    assert pitagoricas3(n) == r

# La comprobación es
#    src> poetry run pytest -q ternas_pitagoricas.py
#    1 passed in 1.83s

# Comparación de eficiencia de pitagoricas
# ======================================

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('pitagoricas1(200)')
#    4.76 segundos
#    >>> tiempo('pitagoricas2(200)')
#    0.69 segundos
#    >>> tiempo('pitagoricas3(200)')
#    0.02 segundos

El código se encuentra en GitHub.