Sucesión con radicales en Haskell
Uno de los problemas de las Olimpiadas matemáticas de este año es el siguiente
Dada la sucesión, definida por
,
calcular el término 2013 de la misma.
A partir del problema he elaborado, con la colaboración de María J. Hidalgo, la siguiente relación de ejercicios en Haskell para la asignatura de Informática (de 1º del Grado en Matemáticas).
En la relación se presenta 5 definiciones distintas de la sucesión:
- la primera es traducción directa usando números flotantes con doble precisión,
- la segunda es una adaptación de la anterior usando números enteros,
- la tercera es una definición sin radicales basada en propiedades de la sucesión conjeturadas usando la segunda definición,
- la cuarta es una versión con memoria de la anterior y
- la quinta es una traducción directa usando números construibles mediante la librería Data.Real.Constructible.
Se observa que las dos primeras definiciones son incorrectas (debido a errores de redondeo), la tercera es correcta pero basada en propiedades no evidentes y además es ineficiente, la cuarta es más eficiente y la quinta es correcta, elemental y eficiente.
La relación de ejercicios, y sus soluciones, es la siguiente
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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
-- --------------------------------------------------------------------- -- § Librerías auxiliares -- -- --------------------------------------------------------------------- import Data.Real.Constructible -- --------------------------------------------------------------------- -- § Primera definición -- -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 1. Definir la función -- suc1 :: Double -> Double -- tal que (suc1 n) es el n-ésimo término de la sucesión x(n) tal que -- x(0) = 1 -- x(n+1) = 2*x(n)+sqrt(3*x(n)^2 -2) -- Por ejemplo, -- suc1 9 == 110771.0 -- --------------------------------------------------------------------- suc1 :: Double -> Double suc1 0 = 1 suc1 n = 2*y + sqrt(3*y^2-2) where y = suc1 (n-1) -- --------------------------------------------------------------------- -- Ejercicio 2. Calcular los 10 primeros términos de la sucesión suc1. -- ¿Qué se observa? -- --------------------------------------------------------------------- -- El cálculo es -- ghci> [suc1 n | n <- [0..9]] -- [1.0,3.0,11.0,41.0,153.0,571.0,2131.0,7953.0,29681.0,110771.0] -- -- Se observa que son números enteros. -- --------------------------------------------------------------------- -- Ejercicio 3. Calcular el valor de (suc1 n) para n entre 270 y 279. -- ¿Qué se observa? -- --------------------------------------------------------------------- -- El cálculo es -- ghci> [suc1 n | n <- [269..272]] -- [5.6336314869343334e153,2.1024998940358734e154,Infinity,Infinity] -- -- Se observa que, a partir de n=271, el valor de (suc1 n) es Infinity . -- --------------------------------------------------------------------- -- § Segunda definición -- -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 4. Definir la función -- suc2 :: Int -> Integer -- tal que (suc2 n) es el n-ésimo término de la sucesión x(n) tal que -- x(0) = 1 -- x(n+1) = 2*x(n)+sqrt(3*x(n)^2 -2) -- Por ejemplo, -- suc2 9 == 110771 -- --------------------------------------------------------------------- suc2 :: Int -> Integer suc2 0 = 1 suc2 n = 2*floor y + floor (sqrt(3*y^2-2)) where y = fromIntegral (suc2 (n-1)) -- --------------------------------------------------------------------- -- Ejercicio 5. Calcular los 10 primeros términos de la sucesión suc2. -- ¿Qué se observa? -- --------------------------------------------------------------------- -- El cálculo es -- ghci> [suc2 n | n <- [0..9]] -- [1,3,11,41,153,571,2131,7953,29681,110771] -- -- Se observa que coincide con los de suc1. -- --------------------------------------------------------------------- -- Ejercicio 6. Calcular el valor de (suc1 271) y (suc2 271) ¿Qué se -- observa? -- --------------------------------------------------------------------- -- El cálculo es -- ghci> suc1 271 -- Infinity -- ghci> suc2 271 -- 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474166427765774142334213821161990973990483643290782815647878226598877573710485167378404229346650077465677328722295309879585030541721400976037074083503612624896 -- -- Se observa que los valores son distintos. -- --------------------------------------------------------------------- -- Ejercicio 7. Calcular el valor de (suc2 2013) ¿Es seguro que el valor -- es correcto? -- --------------------------------------------------------------------- -- El cálculo -- ghci> suc2 2013 -- 539307940458694772318791557236707420085393093682691971820290243473198027416502889398125431967222608063360341639614180072976369306443249867478542291918422373133303680274596455828906658803738282358359248856255017306514452047027388644421739331622481711490051532053758894719841737815439148914506068988872672411648 -- -- No es seguro que el valor sea correcto porque se usa operaciones -- aproximadas como sqrt cuyo tipo es -- sqrt :: Floating a => a -> a -- --------------------------------------------------------------------- -- § Tercera definición -- -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 8. Definir la función -- adyacentes :: [a] -> [(a,a)] -- tal que (adyacentes xs) es la lista de elementos adyacentes en la -- lista xs. Por ejemplo, -- adyacentes [3,2,5,1] == [(3,2),(2,5),(5,1)] -- --------------------------------------------------------------------- adyacentes :: [a] -> [(a,a)] adyacentes xs = zip xs (tail xs) -- --------------------------------------------------------------------- -- Ejercicio 9. Definir la constante -- pares :: [(Integer,Integer)] -- cuyo valor es la lista de pares de elementos de suc2. Por ejemplo, -- take 5 pares == [(3,11),(11,41),(41,153),(153,571),(571,2131)] -- --------------------------------------------------------------------- pares :: [(Integer,Integer)] pares = adyacentes [suc2 n | n <- [1..]] -- --------------------------------------------------------------------- -- Ejercicio 10. Definir la constante -- cocientes :: [Integer] -- cuyo valor es la lista de los cocientes entre (suc2 n) y (suc2 n-1) -- Calcular los 10 primeros cocientes. ¿Qué se observa? -- --------------------------------------------------------------------- cocientes :: [Integer] cocientes = [y `div` x | (x,y) <- pares] -- El cálculo es -- ghci> take 10 cocientes -- [3,3,3,3,3,3,3,3,3,3] -- -- Se observa que todos los cocientes son iguales a 3. -- --------------------------------------------------------------------- -- Ejercicio 11. Definir las constantes -- restos :: [Integer] -- diferencias :: [Integer] -- cuyos valores son las listas de los restos entre (suc2 n) y (suc2 n-1) -- y las diferencias entre (suc2 n) y (suc2 n-1). Calcular los 10 -- primeros restos y las 10 primeras diferencias. ¿Qué se observa? -- --------------------------------------------------------------------- restos :: [Integer] restos = [y `rem` x | (x,y) <- pares] diferencias :: [Integer] diferencias = [y - x | (x,y) <- pares] -- El cálculo es -- ghci> take 10 restos -- [2,8,30,112,418,1560,5822,21728,81090,302632] -- ghci> take 10 diferencias -- [8,30,112,418,1560,5822,21728,81090,302632,1129438] -- -- Se observa que (tail restos) = diferencias; es decir, si n > 1, -- entonces el resto de dividir x(n) entre x(n-1) es igual a x(n-1) -- menos x(n-2). -- --------------------------------------------------------------------- -- Ejercicio 12. A partir de los ejercicios anteriores, redefinir la -- sucesión x(n) sin usar raíces cuadradas. -- --------------------------------------------------------------------- -- Por el ejercicio 10, el cociente entero de x(n) entre x(n-1) es 3 y, -- por el ejercicio 11, el resto es x(n-1) menos x(n-1). Por tanto, -- si n > 1 se tiene -- x(n) = 3*x(n-1) + (x(n-1) - x(n-2)) -- = 4*x(n-1) - x(n-2) -- Además, -- x(0) = 1 -- x(1) = 3 -- --------------------------------------------------------------------- -- Ejercicio 13. Definir la función -- suc3 :: Int -> Integer -- tal que (suc3 n) es el n-ésimo término de la sucesión calculado a -- partir de las relaciones del ejercicio anterior. -- --------------------------------------------------------------------- suc3 :: Int -> Integer suc3 0 = 1 suc3 1 = 3 suc3 n = 4 * suc3 (n-1) - suc3 (n-2) -- --------------------------------------------------------------------- -- Ejercicio 14. Calcular el primer número n tal que (suc2 n) y (suc3 n) -- son distintos. -- --------------------------------------------------------------------- -- El cálculo es -- ghci> head [n | n <- [0..], suc2 n /= suc3 n ] -- 29 -- -- En efecto, -- ghci> suc2 29 -- 30435260762459852 -- ghci> suc3 29 -- 30435260762459851 -- --------------------------------------------------------------------- -- Ejercicio 15. Calcular las estadísticas para calcular (suc3 30). -- --------------------------------------------------------------------- -- El cálculo es -- ghci> :set +s -- ghci> suc3 30 -- 113585939507107651 -- (10.58 secs, 308573992 bytes) -- --------------------------------------------------------------------- -- § Cuarta definición -- -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 16. Definir, con memorización, la constante -- terminosSuc4 :: [Integer] -- cuyo valor es la lista de los términos de la sucesión- Por ejemplo, -- ghci> take 10 terminosSuc4 -- [1,3,11,41,153,571,2131,7953,29681,110771] -- --------------------------------------------------------------------- terminosSuc4 :: [Integer] terminosSuc4 = 1 : 3 : zipWith f terminosSuc4 (tail terminosSuc4) where f a b = 4*b-a -- --------------------------------------------------------------------- -- Ejercicio 17. Definir, usando el ejercicio anterior, la función -- suc4 :: Int -> Integer -- tal que (suc4 n) es el n-ésimo término de la sucesión. Por ejemplo, -- suc4 9 == 110771 -- --------------------------------------------------------------------- suc4 :: Int -> Integer suc4 n = terminosSuc4 !! n -- --------------------------------------------------------------------- -- Ejercicio 18. Calcular las estadísticas para calcular (suc4 30). -- --------------------------------------------------------------------- -- El cálculo es -- ghci> suc4 30 -- 113585939507107651 -- (0.01 secs, 514024 bytes) -- --------------------------------------------------------------------- -- Ejercicio 19. Calcular el valor (suc4 2013) y compararlo con -- (suc2 2013) calculada en el ejercicio 7. ¿Qué se observa? -- --------------------------------------------------------------------- -- El cálculo es -- ghci> suc6 2013 -- 168776250022825386299444353956146044460247790742873687582016133344522778834838119356347990774063576046090482033035139781143578827887856444672702026046129704662452685502970573398959704390641212469508877669676385079967305749285619309371243721828379393663082046352880287021533203235565273595398911918334776813716437912906145378621573160747223490630284199813949162867666143722222198554542704883958146656862955220278405352456921674979356418306447479925189466207568278514262313094775498075311079939520159895669319197545406726501442522056327512294217936777501198964667044981645594285486625037252918910100964709474363205640133571220174702869751355440184294783274959230759397713358696912162786998522539605439904172284196408952804589968814256644505539555966788601728476250422330377288011399953887869866071982694327789456353900043868106892040957784702635555737001663424349147133198274906620670361879190816303348127152538837067889974857620282804630592816383493496381502850806685327131505567094035597112342874567493562447260405834933418947862442299950353801786735106018538806097833792417294595444154254566097806788362345007575154748269209956755993320683892467446091 -- -- Se observa que el resultado es distinto. -- --------------------------------------------------------------------- -- § Quinta definición -- -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 20. Definir, usando la librería Data.Real.Constructible, la -- función -- suc5 :: Integer -> Construct -- tal que (suc5 n) es el n-ésimo término de la sucesión. Por ejemplo, -- suc5 9 == 110771 -- --------------------------------------------------------------------- suc5:: Integer -> Construct suc5 0 = 1 suc5 n = 2*y + sqrt(3*y^2-2) where y = suc5 (n-1) -- --------------------------------------------------------------------- -- Ejercicio 21. Comprobar que (suc5 2013) y (suc4 2013) son iguales. -- --------------------------------------------------------------------- -- La comprobación es -- ghci> fromIntegral (suc4 2013) == fromConstruct (suc5 2013) -- True |