{"id":5702,"date":"2017-02-15T18:20:43","date_gmt":"2017-02-15T17:20:43","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/?p=5702"},"modified":"2017-02-15T18:23:20","modified_gmt":"2017-02-15T17:23:20","slug":"i1m2016-calculo-numerico-en-haskell","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/i1m2016-calculo-numerico-en-haskell\/","title":{"rendered":"I1M2016: C\u00e1lculo num\u00e9rico en Haskell"},"content":{"rendered":"<p>En la clase de hoy de <a href=\"http:\/\/www.cs.us.es\/~jalonso\/cursos\/i1m-16\">Inform\u00e1tica de 1\u00ba del Grado en Matem\u00e1ticas<\/a> se han explicado las soluciones de los ejercicios de la relaci\u00f3n 18, en la que se definen funciones para resolver los siguientes problemas de c\u00e1lculo num\u00e9rico:<\/p>\n<ul>\n<li>diferenciaci\u00f3n num\u00e9rica,<\/li>\n<li>c\u00e1lculo de la ra\u00edz cuadrada mediante el m\u00e9todo de Her\u00f3n,<\/li>\n<li>c\u00e1lculo de los ceros de una funci\u00f3n por el m\u00e9todo de Newton y<\/li>\n<li>c\u00e1lculo de funciones inversas.<\/li>\n<\/ul>\n<p>Un aspecto a destacar desde el punto de vista de la programaci\u00f3n es el uso de la abstracci\u00f3n de procedimientos.<\/p>\n<p>Los ejercicios, y sus soluciones, se muestran a continuaci\u00f3n.<br \/>\n<!--more--><\/p>\n<pre lang=\"haskell\">\n-- ---------------------------------------------------------------------\n-- Importaci\u00f3n de librer\u00edas                                           --\n-- ---------------------------------------------------------------------\n\nimport Test.QuickCheck\n\n-- ---------------------------------------------------------------------\n-- Diferenciaci\u00f3n num\u00e9rica                                            --\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 1.1. Definir la funci\u00f3n\n--    derivada :: Double -> (Double -> Double) -> Double -> Double\n-- tal que (derivada a f x) es el valor de la derivada de la funci\u00f3n f\n-- en el punto x con aproximaci\u00f3n a. Por ejemplo, \n--    derivada 0.001 sin pi  ==  -0.9999998333332315\n--    derivada 0.001 cos pi  ==  4.999999583255033e-4\n-- ---------------------------------------------------------------------\n\nderivada :: Double -> (Double -> Double) -> Double -> Double\nderivada a f x = (f(x+a)-f(x))\/a  \n\n-- ---------------------------------------------------------------------\n-- Ejercicio 1.2. Definir las funciones\n--    derivadaBurda :: (Double -> Double) -> Double -> Double\n--    derivadaFina  :: (Double -> Double) -> Double -> Double\n--    derivadaSuper :: (Double -> Double) -> Double -> Double\n-- tales que \n--    * (derivadaBurda f x) es el valor de la derivada de la funci\u00f3n f \n--      en el punto x con aproximaci\u00f3n 0.01,\n--    * (derivadaFina f x) es el valor de la derivada de la funci\u00f3n f \n--      en el punto x con aproximaci\u00f3n 0.0001.\n--    * (derivadauperBurda f x) es el valor de la derivada de la funci\u00f3n f \n--      en el punto x con aproximaci\u00f3n 0.000001.\n-- Por ejemplo,\n--    derivadaBurda cos pi  ==  4.999958333473664e-3\n--    derivadaFina  cos pi  ==  4.999999969612645e-5\n--    derivadaSuper cos pi  ==  5.000444502911705e-7\n-- ---------------------------------------------------------------------\n\nderivadaBurda :: (Double -> Double) -> Double -> Double\nderivadaBurda = derivada 0.01  \n\nderivadaFina :: (Double -> Double) -> Double -> Double\nderivadaFina  = derivada 0.0001  \n\nderivadaSuper :: (Double -> Double) -> Double -> Double\nderivadaSuper = derivada 0.000001  \n\n-- ---------------------------------------------------------------------\n-- Ejercicio 1.3. Definir la funci\u00f3n\n--    derivadaFinaDelSeno :: Double -> Double\n-- tal que (derivadaFinaDelSeno x) es el valor de la derivada fina del\n-- seno en x. Por ejemplo,\n--    derivadaFinaDelSeno pi  ==  -0.9999999983354436\n-- ---------------------------------------------------------------------\n\nderivadaFinaDelSeno :: Double -> Double\nderivadaFinaDelSeno = derivadaFina sin  \n\n-- ---------------------------------------------------------------------\n-- C\u00e1lculo de la ra\u00edz cuadrada                                        --\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 2.1. En los siguientes apartados de este ejercicio se va a\n-- calcular la ra\u00edz cuadrada de un n\u00famero bas\u00e1ndose en las siguientes\n-- propiedades:\n-- * Si y es una aproximaci\u00f3n de la ra\u00edz cuadrada de x, entonces \n--   (y+x\/y)\/2 es una aproximaci\u00f3n mejor. \n-- * El l\u00edmite de la sucesi\u00f3n definida por \n--       x_0     = 1 \n--       x_{n+1} = (x_n+x\/x_n)\/2\n--   es la ra\u00edz cuadrada de x.\n-- \n-- Definir, por iteraci\u00f3n con until, la funci\u00f3n\n--    raiz :: Double -> Double\n-- tal que (raiz x) es la ra\u00edz cuadrada de x calculada usando la\n-- propiedad anterior con una aproximaci\u00f3n de 0.00001 y tomando como\n-- v. Por ejemplo, \n--    raiz 9  ==  3.000000001396984\n-- ---------------------------------------------------------------------\n\nraiz :: Double -> Double\nraiz x = raizA 1\n    where raizA y | aceptable y = y\n                  | otherwise   = raizA (mejora y)\n          mejora y    = 0.5*(y+x\/y)\n          aceptable y = abs(y*y-x) < 0.00001\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 3.2. Definir el operador \n--    (~=) :: Double -> Double -> Bool\n-- tal que (x ~= y) si |x-y| < 0.001. Por ejemplo,\n--    3.05 ~= 3.07        ==  False\n--    3.00005 ~= 3.00007  == True\n-- ---------------------------------------------------------------------\n\ninfix 5 ~=\n(~=) :: Double -> Double -> Bool\nx ~= y = abs(x-y) < 0.001\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 3.3. Comprobar con QuickCheck que si x es positivo,\n-- entonces \n--    (raiz x)^2 ~= x\n-- ---------------------------------------------------------------------\n\n-- La propiedad es\nprop_raiz :: Double -> Bool\nprop_raiz x =\n    (raiz x1)^2 ~= x1\n    where x1 = abs x\n\n-- La comprobaci\u00f3n es\n--    ghci> quickCheck prop_raiz\n--    OK, passed 100 tests.\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 3.4. Definir por recursi\u00f3n la funci\u00f3n\n--    until1 :: (a -> Bool) -> (a -> a) -> a -> a\n-- tal que (until1 p f x) es el resultado de aplicar la funci\u00f3n f a x el\n-- menor n\u00famero posible de veces, hasta alcanzar un valor que satisface\n-- el predicado p. Por ejemplo, \n--    until1 (>1000) (2*) 1  ==  1024\n-- Nota: until1 es equivalente a la predefinida until.\n-- ---------------------------------------------------------------------\n\nuntil1 :: (a -> Bool) -> (a -> a) -> a -> a\nuntil1 p f x  | p x       = x\n              | otherwise = until1 p f (f x)\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 3.5. Definir, por iteraci\u00f3n con until, la funci\u00f3n\n--    raizI :: Double -> Double\n-- tal que (raizI x) es la ra\u00edz cuadrada de x calculada usando la\n-- propiedad anterior. Por ejemplo, \n--    raizI 9  ==  3.000000001396984\n-- ---------------------------------------------------------------------\n\nraizI :: Double -> Double\nraizI x = until aceptable mejora 1\n          where mejora y    = 0.5*(y+x\/y)\n                aceptable y = abs(y*y-x) < 0.00001\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 3.6. Comprobar con QuickCheck que si x es positivo,\n-- entonces \n--    (raizI x)^2 ~= x\n-- ---------------------------------------------------------------------\n\n-- La propiedad es\nprop_raizI :: Double -> Bool\nprop_raizI x =\n    (raizI x1)^2 ~= x1\n    where x1 = abs x           \n\n-- La comprobaci\u00f3n es\n--    ghci> quickCheck prop_raizI\n--    OK, passed 100 tests.\n\n-- ---------------------------------------------------------------------\n-- Ceros de una funci\u00f3n                                               --\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 4. Los ceros de una funci\u00f3n pueden calcularse mediante el\n-- m\u00e9todo de Newton bas\u00e1ndose en las siguientes propiedades:\n-- * Si b es una aproximaci\u00f3n para el punto cero de f, entonces \n--   b-f(b)\/f'(b) es una mejor aproximaci\u00f3n.\n-- * el l\u00edmite de la sucesi\u00f3n x_n definida por\n--      x_0     = 1 \n--      x_{n+1} = x_n-f(x_n)\/f'(x_n)\n--   es un cero de f.\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 4.1. Definir por recursi\u00f3n la funci\u00f3n\n--    puntoCero :: (Double -> Double) -> Double\n-- tal que (puntoCero f) es un cero de la funci\u00f3n f calculado usando la\n-- propiedad anterior. Por ejemplo, \n--    puntoCero cos  ==  1.5707963267949576\n-- ---------------------------------------------------------------------\n\npuntoCero :: (Double -> Double) -> Double\npuntoCero f = puntoCero1 f 1\n    where puntoCero1 f x | aceptable x = x\n                         | otherwise   = puntoCero1 f (mejora x)\n          mejora b    = b - f b \/ derivadaFina f b\n          aceptable b = abs (f b) < 0.00001\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 4.2. Definir, por iteraci\u00f3n con until, la funci\u00f3n\n--    puntoCeroI :: (Double -> Double) -> Double\n-- tal que (puntoCeroI f) es un cero de la funci\u00f3n f calculado usando la\n-- propiedad anterior. Por ejemplo, \n--    puntoCeroI cos  ==  1.5707963267949576\n-- ---------------------------------------------------------------------\n\npuntoCeroI :: (Double -> Double) -> Double\npuntoCeroI f = until aceptable mejora 1\n    where mejora b    = b - f b \/ derivadaFina f b\n          aceptable b = abs (f b) < 0.00001\n\n-- ---------------------------------------------------------------------\n-- Funciones inversas                                                 --\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5. En este ejercicio se usar\u00e1 la funci\u00f3n puntoCero para\n-- definir la inversa de distintas funciones.\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.1. Definir, usando puntoCero, la funci\u00f3n\n--    raizCuadrada :: Double -> Double\n-- tal que (raizCuadrada x) es la ra\u00edz cuadrada de x. Por ejemplo,\n--    raizCuadrada 9  ==  3.000000002941184\n-- ---------------------------------------------------------------------\n\nraizCuadrada :: Double -> Double\nraizCuadrada a = puntoCero f\n    where f x = x*x-a  \n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.2. Comprobar con QuickCheck que si x es positivo,\n-- entonces \n--    (raizCuadrada x)^2 ~= x\n-- ---------------------------------------------------------------------\n\n-- La propiedad es\nprop_raizCuadrada :: Double -> Bool\nprop_raizCuadrada x =\n    (raizCuadrada x1)^2 ~= x1\n    where x1 = abs x\n\n-- La comprobaci\u00f3n es\n--    ghci> quickCheck prop_raizCuadrada\n--    OK, passed 100 tests.\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.3. Definir, usando puntoCero, la funci\u00f3n\n--    raizCubica :: Double -> Double\n-- tal que (raizCubica x) es la ra\u00edz cuadrada de x. Por ejemplo,\n--    raizCubica 27  ==  3.0000000000196048\n-- ---------------------------------------------------------------------\n\nraizCubica :: Double -> Double\nraizCubica a = puntoCero f\n    where f x = x*x*x-a \n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.4. Comprobar con QuickCheck que si x es positivo,\n-- entonces \n--    (raizCubica x)^3 ~= x\n-- ---------------------------------------------------------------------\n\n-- La propiedad es\nprop_raizCubica :: Double -> Bool\nprop_raizCubica x =\n    (raizCubica x)^3 ~= x\n    where x1 = abs x\n\n-- La comprobaci\u00f3n es\n--    ghci> quickCheck prop_raizCubica\n--    OK, passed 100 tests.\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.5. Definir, usando puntoCero, la funci\u00f3n\n--    arcoseno :: Double -> Double\n-- tal que (arcoseno x) es el arcoseno de x. Por ejemplo,\n--    arcoseno 1  == 1.5665489428306574\n-- ---------------------------------------------------------------------\n\narcoseno :: Double -> Double\narcoseno a = puntoCero f\n    where f x = sin x - a  \n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.6. Comprobar con QuickCheck que si x est\u00e1 entre 0 y 1,\n-- entonces \n--    sin (arcoseno x) ~= x\n-- ---------------------------------------------------------------------\n\n-- La propiedad es\nprop_arcoseno :: Double -> Bool\nprop_arcoseno x =\n    sin (arcoseno x1) ~= x1\n    where x1 = abs (x - fromIntegral (truncate x))\n\n-- La comprobaci\u00f3n es\n--    ghci> quickCheck prop_arcoseno\n--    OK, passed 100 tests.\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.7. Definir, usando puntoCero, la funci\u00f3n\n--    arcocoseno :: Double -> Double\n-- tal que (arcoseno x) es el arcoseno de x. Por ejemplo,\n--    arcocoseno 0  == 1.5707963267949576\n-- ---------------------------------------------------------------------\n\narcocoseno :: Double -> Double\narcocoseno a = puntoCero f\n    where f x = cos x - a  \n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.8. Comprobar con QuickCheck que si x est\u00e1 entre 0 y 1,\n-- entonces \n--    cos (arcocoseno x) ~= x\n-- ---------------------------------------------------------------------\n\n-- La propiedad es\nprop_arcocoseno :: Double -> Bool\nprop_arcocoseno x =\n    cos (arcocoseno x1) ~= x1\n    where x1 = abs (x - fromIntegral (truncate x))\n\n-- La comprobaci\u00f3n es\n--    ghci> quickCheck prop_arcocoseno\n--    OK, passed 100 tests.\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.7. Definir, usando puntoCero, la funci\u00f3n\n--    inversa :: (Double -> Double) -> Double -> Double\n-- tal que (inversa g x) es el valor de la inversa de g en x. Por\n-- ejemplo, \n--    inversa (^2) 9  ==  3.000000002941184\n-- ---------------------------------------------------------------------\n\ninversa :: (Double -> Double) -> Double -> Double\ninversa g a = puntoCero f\n    where f x = g x - a  \n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5.8. Redefinir, usando inversa, las funciones raizCuadrada,\n-- raizCubica, arcoseno y arcocoseno.\n-- ---------------------------------------------------------------------\n\nraizCuadrada1 = inversa (^2)\nraizCubica1   = inversa (^3)\narcoseno1     = inversa sin  \narcocoseno1   = inversa cos\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>En la clase de hoy de Inform\u00e1tica de 1\u00ba del Grado en Matem\u00e1ticas se han explicado las soluciones de los ejercicios de la relaci\u00f3n 18, en la que se definen funciones para resolver los siguientes problemas de c\u00e1lculo num\u00e9rico: diferenciaci\u00f3n num\u00e9rica, c\u00e1lculo de la ra\u00edz cuadrada mediante el m\u00e9todo de Her\u00f3n, c\u00e1lculo de los ceros&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false},"categories":[260],"tags":[270,313],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/5702"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/comments?post=5702"}],"version-history":[{"count":1,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/5702\/revisions"}],"predecessor-version":[{"id":5703,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/5702\/revisions\/5703"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/media?parent=5702"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/categories?post=5702"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/tags?post=5702"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}