{"id":2273,"date":"2016-04-01T06:00:17","date_gmt":"2016-04-01T04:00:17","guid":{"rendered":"http:\/\/www.glc.us.es\/~jalonso\/exercitium\/?p=2273"},"modified":"2016-04-08T06:07:53","modified_gmt":"2016-04-08T04:07:53","slug":"representacion-decimal-de-numeros-racionales","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/representacion-decimal-de-numeros-racionales\/","title":{"rendered":"Representaci\u00f3n decimal de n\u00fameros racionales"},"content":{"rendered":"<p>Los n\u00fameros decimales se representan por ternas, donde el primer elemento es la parte entera, el segundo es el anteper\u00edodo y el tercero es el per\u00edodo. Por ejemplo,<\/p>\n<pre lang=\"text\">\n    6\/2  = 3                  se representa por (3,[],[])\n    1\/2  = 0.5                se representa por (0,[5],[])\n    1\/3  = 0.333333...        se representa por (0,[],[3])  \n   23\/14 = 1.6428571428571... se representa por (1,[6],[4,2,8,5,7,1])\n<\/pre>\n<p>Su tipo es<\/p>\n<pre lang=\"text\">\n   type Decimal = (Integer,[Integer],[Integer])\n<\/pre>\n<p>Los n\u00fameros racionales se representan por un par de enteros, donde el  primer elemento es el numerador y el segundo el denominador. Por ejemplo, el n\u00famero 2\/3 se representa por (2,3). Su tipo es<\/p>\n<pre lang=\"text\">\n   type Racional = (Integer,Integer)\n<\/pre>\n<p>Definir las funciones<\/p>\n<pre lang=\"text\">\n   decimal  :: Racional -> Decimal\n   racional :: Decimal -> Racional\n<\/pre>\n<p>tales que<\/p>\n<ul>\n<li>(decimal r) es la representaci\u00f3n decimal del n\u00famero racional r. Por ejemplo, <\/li>\n<\/ul>\n<pre lang=\"text\">\n        decimal (1,4)    ==  (0,[2,5],[])\n        decimal (1,3)    ==  (0,[],[3])\n        decimal (23,14)  ==  (1,[6],[4,2,8,5,7,1])\n<\/pre>\n<ul>\n<li>(racional d) es el n\u00famero racional cuya representaci\u00f3n decimal es d. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n        racional (0,[2,5],[])           ==  (1,4)\n        racional (0,[],[3])             ==  (1,3)\n        racional (1,[6],[4,2,8,5,7,1])  ==  (23,14)\n<\/pre>\n<p>Con la funci\u00f3n decimal se puede calcular los per\u00edodos de los n\u00fameros racionales. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   ghci> let (_,_,p) = decimal (23,14) in concatMap show p\n   \"428571\"\n   ghci> let (_,_,p) = decimal (1,47) in concatMap show p\n   \"0212765957446808510638297872340425531914893617\"\n   ghci> let (_,_,p) = decimal (1,541) in length (concatMap show p)\n   540\n<\/pre>\n<p>Comprobar con QuickCheck si las funciones decimal y racional son inversas.<\/p>\n<h4>Soluciones<\/h4>\n<pre lang=\"haskell\">\n-- ---------------------------------------------------------------------\n-- \u00a7 Librer\u00edas auxiliares                                             --\n-- ---------------------------------------------------------------------\n\nimport Data.List\nimport Test.QuickCheck\n\n-- ---------------------------------------------------------------------\n-- \u00a7 Tipos                                                            --\n-- ---------------------------------------------------------------------\n\n-- Un n\u00famero racional se representa por un par de enteros, donde el\n-- primer elemento es el numerador y el segundo el denominador.\ntype Racional = (Integer,Integer)\n\n-- Un n\u00famero decimal es una terna donde el primer elemento es la parte\n-- entera, el segundo es el anteper\u00edodo y el tercero es el per\u00edodo.\ntype Decimal = (Integer,[Integer],[Integer])\n\n-- ---------------------------------------------------------------------\n-- \u00a7 De racional a decimal                                            --\n-- ---------------------------------------------------------------------\n\n-- (mayorExponente a x) es el mayor n tal que a^n divide a x. Por ejemplo,\n--    mayorExponente 2 40  ==  3\n--    mayorExponente 5 40  ==  1\n--    mayorExponente 5 41  ==  0\nmayorExponente :: Integer -> Integer -> Integer\nmayorExponente a x = head [n | n <- [1..], mod x (a^n) \/= 0] - 1\n\n-- (longitudAnteperiodo n) es la longitud del anteper\u00edodo de 1\/n (y de\n-- cualquier fracci\u00f3n irreducible de denominador n). Por ejemplo, \n--    longitudAnteperiodo 2   ==  1\n--    longitudAnteperiodo 3   ==  0\n--    longitudAnteperiodo 14  ==  1\nlongitudAnteperiodo :: Integer -> Integer\nlongitudAnteperiodo n = max (mayorExponente 2 n) (mayorExponente 5 n)\n\n-- (longitudPeriodo n) es la longitud del per\u00edodo de 1\/n (y de\n-- cualquier fracci\u00f3n irreducible de denominador n). Por ejemplo, \n--    longitudPeriodo 2  ==  0\n--    longitudPeriodo 3  ==  1\n--    longitudPeriodo 7  ==  6\nlongitudPeriodo :: Integer -> Integer\nlongitudPeriodo n\n    | m == 1    = 0 \n    | otherwise = head [k | k <- [1..], (10^k) `mod` m == 1]\n    where m = n `div` (2^(mayorExponente 2 n) * 5^(mayorExponente 5 n))\n\n-- (expansionDec (x,y)) es la expansi\u00f3n decimal de x\/y. Por ejemplo, \n--    take 10 (expansionDec (1,4))    ==  [0,2,5]\n--    take 10 (expansionDec (1,7))    ==  [0,1,4,2,8,5,7,1,4,2]\n--    take 12 (expansionDec (90,7))   ==  [12,8,5,7,1,4,2,8,5,7,1,4]\n--    take 12 (expansionDec (23,14))  ==  [1,6,4,2,8,5,7,1,4,2,8,5]\nexpansionDec :: Racional -> [Integer]\nexpansionDec (x,y) \n    | r == 0    = [q] \n    | otherwise = q : expansionDec (r*10,y)\n    where (q,r) = quotRem x y\n\n-- (parteEntera (a,b)) es la parte entera de a\/b. Por ejemplo,\n--    parteEntera (125,3)  ==  41\nparteEntera :: Racional -> Integer\nparteEntera (a,b) = a `div` b\n\n-- (antePeriodo (a,b)) es el anteper\u00edodo de a\/b; es decir, la lista de\n-- cifras que se encuentran entre la parte entera y el primer per\u00edodo de\n-- a\/b. Por ejemplo,\n--    antePeriodo (23,14)  ==  [6]\n--    antePeriodo (1,5)    ==  [2]\nantePeriodo :: Racional -> [Integer]\nantePeriodo (a,b) = genericTake s (tail xs)\n    where xs = expansionDec (a,b)\n          s  = longitudAnteperiodo b\n\n-- (periodo (a,b)) es el per\u00edodo de a\/b; es decir, la lista de cifras que\n-- se encuentran entre la parte entera y el primer per\u00edodo de a\/b. Por\n-- ejemplo, \n--    periodo (1,3)                   ==  [3]\n--    periodo (1,5)                   ==  []\n--    periodo (1,7)                   ==  [1,4,2,8,5,7]\n--    periodo (23,14)                 ==  [4,2,8,5,7,1]\n--    concatMap show $ periodo (1,29) == \"0344827586206896551724137931\"\nperiodo :: Racional -> [Integer]\nperiodo (a,b) = genericTake t (genericDrop (1+s) xs)\n    where xs = expansionDec (a,b)\n          s  = longitudAnteperiodo b\n          t  = longitudPeriodo b\n\n-- (reducido (a,b)) es la forma reducida del n\u00famero racional a\/b. Por\n-- ejemplo, \n--    reducido (40,80)  ==  (1,2)\nreducido :: Racional -> Racional\nreducido (a,b) = (a `div` m, b `div` m) \n    where m = gcd a b\n\n-- (decimal (x,y)) es la forma decimal de x\/y; es decir, la terna\n-- formada por la parte entera, la parte decimal pura y la parte decimal\n-- peri\u00f3dica. Por ejemplo, \n--    decimal (1,4)    ==  (0,[2,5],[])\n--    decimal (1,3)    ==  (0,[],[3])\n--    decimal (23,14)  ==  (1,[6],[4,2,8,5,7,1])\ndecimal :: Racional -> Decimal\ndecimal (a,b) = (parteEntera r, antePeriodo r, periodo r)\n    where r = reducido (a,b)\n\n-- ---------------------------------------------------------------------\n-- \u00a7 De decimal a racional                                            --\n-- ---------------------------------------------------------------------\n\n-- (digitosAnumero xs) es el n\u00famero correspondiente a la lista de\n-- d\u00edgitos xs. Por ejemplo,\n--    digitosAnumero [3,2,5]  ==  325\ndigitosAnumero :: [Integer] -> Integer\ndigitosAnumero = foldl (\\a y -> 10*a+y) 0\n\n-- 2\u00aa definici\u00f3n de digitosAnumero (por comprensi\u00f3n)\ndigitosAnumero2 :: [Integer] -> Integer\ndigitosAnumero2 xs = sum [x*(10^i) | (x,i) <- zip xs [n-1,n-2..0]]\n    where n = length xs\n\n-- (racional (x,ys,zs)) es el n\u00famero racional cuya representaci\u00f3n\n-- decimal es (x,ys,zs). Por ejemplo,\n--    racional (0,[2,5],[])           ==  (1,4)\n--    racional (0,[],[3])             ==  (1,3)\n--    racional (1,[6],[4,2,8,5,7,1])  ==  (23,14)\nracional :: Decimal -> Racional\nracional (x,ys,[]) = reducido (a,b) where\n    a = digitosAnumero (x:ys)\n    b = 10^(length ys)\nracional (x,ys,zs) = reducido (a,b) where \n    a = digitosAnumero (x:ys++zs) - digitosAnumero (x:ys)\n    b = digitosAnumero (replicate (length zs) 9 ++ replicate (length ys) 0)\n\n-- ---------------------------------------------------------------------\n-- \u00a7 Propiedades                                                      --\n-- ---------------------------------------------------------------------\n\n-- La 1\u00aa propiedad es\nprop_RacionalDecimal :: Racional -> Property\nprop_RacionalDecimal (a,b) =\n    a >= 0 && b > 0  ==>\n    racional (decimal (a,b)) == reducido (a,b)\n\n-- La comprobaci\u00f3n es \n--    ghci> quickCheck prop_RacionalDecimal\n--    +++ OK, passed 100 tests.\n\n-- En lugar de reducido se puede usar un generador de n\u00fameros racionales\nnumeroRacional :: Gen Racional\nnumeroRacional = do a <- arbitrary\n                    b <- arbitrary\n                    return (reducido (abs a, 1+ abs b))\n\n-- La propiedad es\nprop_RacionalDecimal2 :: Property\nprop_RacionalDecimal2 =\n    forAll numeroRacional\n           (\\(a,b) -> racional (decimal (a,b)) == (a,b))\n\n-- La comprobaci\u00f3n es\n--   ghci> quickCheck prop_RacionalDecimal2\n--   +++ OK, passed 100 tests.\n\n-- Para la 2\u00aa propiedad se define un generador de n\u00fameros decimales\nnumeroDecimal :: Gen Decimal\nnumeroDecimal = do a <- arbitrary\n                   b <- arbitrary\n                   return (decimal (abs a, 1+ abs b))\n\n-- La 2\u00aa propiedad es\nprop_DecimalRacional :: Property\nprop_DecimalRacional =\n    forAll numeroDecimal \n           (\\(x,ys,zs) -> decimal (racional (x,ys,zs)) == (x,ys,zs))\n\n-- La comprobaci\u00f3n es\n--   ghci> quickCheck prop_DecimalRacional\n--   +++ OK, passed 100 tests.\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Los n\u00fameros decimales se representan por ternas, donde el primer elemento es la parte entera, el segundo es el anteper\u00edodo y el tercero es el per\u00edodo. Por ejemplo, 6\/2 = 3 se representa por (3,[],[]) 1\/2 = 0.5 se representa por (0,[5],[]) 1\/3 = 0.333333&#8230; se representa por (0,[],[3]) 23\/14 = 1.6428571428571&#8230; se representa por&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","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":[7],"tags":[8,30,185,338,155,337,306,71,28,83,89,11,254,6,19,40,45,146,9],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/2273"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/comments?post=2273"}],"version-history":[{"count":5,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/2273\/revisions"}],"predecessor-version":[{"id":2303,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/2273\/revisions\/2303"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/media?parent=2273"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/categories?post=2273"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/tags?post=2273"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}