Terna pitagórica a partir de un lado
Una terna pitagórica con primer lado x es una terna (x,y,z) tal que x^2 + y^2 = z^2. Por ejemplo, las ternas pitagóricas con primer lado 16 son (16,12,20), (16,30,34) y (16,63,65).
Definir las funciones
1 2 3 |
ternasPitagoricas :: Integer -> [(Integer,Integer,Integer)] mayorTernaPitagorica :: Integer -> (Integer,Integer,Integer) graficaMayorHipotenusa :: Integer -> IO () |
tales que
- (ternasPitgoricas x) es la lista de las ternas pitagóricas con primer lado x. Por ejemplo,
1 2 3 4 |
ternasPitagoricas 16 == [(16,12,20),(16,30,34),(16,63,65)] ternasPitagoricas 20 == [(20,15,25),(20,21,29),(20,48,52),(20,99,101)] ternasPitagoricas 25 == [(25,60,65),(25,312,313)] ternasPitagoricas 26 == [(26,168,170)] |
- (mayorTernaPitagorica x) es la mayor de las ternas pitagóricas con primer lado x. Por ejemplo,
1 2 3 4 5 6 |
mayorTernaPitagorica 16 == (16,63,65) mayorTernaPitagorica 20 == (20,99,101) mayorTernaPitagorica 25 == (25,312,313) mayorTernaPitagorica 26 == (26,168,170) mayorTernaPitagorica 2018 == (2018,1018080,1018082) mayorTernaPitagorica 2019 == (2019,2038180,2038181) |
- (graficaMayorHipotenusa n) dibuja la gráfica de las sucesión de las mayores hipotenusas de las ternas pitagóricas con primer lado x, para x entre 3 y n. Por ejemplo, (graficaMayorHipotenusa 100) dibuja
Soluciones
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 84 85 |
import Graphics.Gnuplot.Simple -- Definición de ternasPitagoricas -- =============================== ternasPitagoricas :: Integer -> [(Integer,Integer,Integer)] ternasPitagoricas x = [(x,y,z) | y <- [1..(x^ 2 - 1) `div` 2 ] , z <- raizCuadrada (x^2 + y^2)] -- La justificación de la cota es -- x > 2 -- x^2 + y^2 >= (y+1)^2 -- x^2 + y^2 >= y^2 + 2*y + 1 -- y =< (x^ 2 - 1) `div` 2 -- (raizCuadrada x) es la lista formada por la raíz cuadrada entera de -- x, si existe y la lista vacía, en caso contrario. Por ejemplo, -- raizCuadrada 25 == [5] -- raizCuadrada 26 == [] raizCuadrada :: Integer -> [Integer] raizCuadrada x = [y | y <- [(round . sqrt . fromIntegral) x] , y^2 == x] -- 1ª definición de mayorTernaPitagorica -- ===================================== mayorTernaPitagorica :: Integer -> (Integer,Integer,Integer) mayorTernaPitagorica = last . ternasPitagoricas -- 2ª definición de mayorTernaPitagorica -- ===================================== mayorTernaPitagorica2 :: Integer -> (Integer,Integer,Integer) mayorTernaPitagorica2 x = head [(x,y,z) | y <- [k, k-1 .. 1] , z <- raizCuadrada (x^2 + y^2)] where k = (x^2 - 1) `div` 2 -- 3ª definición de mayorTernaPitagorica -- ===================================== -- Se supone que x > 2. Se consideran dos casos: -- -- Primer caso: Supongamos que x es par. Entonces x^2 > 4 y es divisible -- por 4. Por tanto, existe un y tal que x^2 = 4*y + 4; luego, -- x^2 + y^2 = 4*y + 4 + y^2 -- = (y + 2)^2 -- La terna es (x,y,y+2) donde y = (x^2 - 4) / 4. -- -- Segundo caso: Supongamos que x es impar. Entonces x^2 es impar. Por -- tanto, existe un y tal que x^2 = 2*y + 1; luego, -- x^2 + y^2 = 2*y + 1 + y^2 -- = (y+1)^2 -- La terna es (x,y,y+1) donde y = (x^2 - 1) / 2. mayorTernaPitagorica3 :: Integer -> (Integer,Integer,Integer) mayorTernaPitagorica3 x | even x = (x, y1, y1 + 2) | otherwise = (x, y2, y2 + 1) where y1 = (x^2 - 4) `div` 4 y2 = (x^2 - 1) `div` 2 -- Comparación de eficiencia -- λ> mayorTernaPitagorica 1006 -- (1006,253008,253010) -- (7.36 secs, 1,407,793,992 bytes) -- λ> mayorTernaPitagorica2 1006 -- (1006,253008,253010) -- (3.76 secs, 704,007,456 bytes) -- λ> mayorTernaPitagorica3 1006 -- (1006,253008,253010) -- (0.01 secs, 157,328 bytes) graficaMayorHipotenusa :: Integer -> IO () graficaMayorHipotenusa n = plotList [ Key Nothing , PNG "Terna_pitagorica_a_partir_de_un_lado.png" ] [(x,z) | x <- [3..n] , let (_,_,z) = mayorTernaPitagorica3 x] |
Otra propuesta de solución buscando las ternas pitagóricas a partir de las ternas primitivas, inspirada en el artículo Generando ternas pitagoricas publicado el 23 de marzo de 2009 por Miguel Ángel Morales en su blog Gaussianos.
Nota: En la definición de ternasPrimitivas pueden aparecer ternas no primitivas o repetidas pero esos casos se solucionan mediante el «nub» de la función ternasPitagoricas.
Falta un detallito en la función ternasPrimasImpares: