{"id":7823,"date":"2022-10-29T10:46:57","date_gmt":"2022-10-29T08:46:57","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/?p=7823"},"modified":"2022-10-29T11:06:39","modified_gmt":"2022-10-29T09:06:39","slug":"pfh-la-semana-en-exercitium-28-de-octubre-de-2022","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/pfh-la-semana-en-exercitium-28-de-octubre-de-2022\/","title":{"rendered":"PFH: La semana en Exercitium (28 de octubre de 2022)"},"content":{"rendered":"<p>Esta semana he publicado en <a href=\"http:\/\/bit.ly\/2sqPtGs\">Exercitium<\/a> las soluciones de los siguientes problemas:<\/p>\n<ul>\n<li><a href=\"#ej1\">1. Base de datos de actividades<\/a><\/li>\n<li><a href=\"#ej2\">2. Potencia entera<\/a><\/li>\n<li><a href=\"#ej3\">3. Algoritmo de Euclides del mcd<\/a><\/li>\n<li><a href=\"#ej4\">4. D\u00edgitos de un n\u00famero<\/a><\/li>\n<li><a href=\"#ej5\">5. Suma de los d\u00edgitos de un n\u00famero<\/a><\/li>\n<\/ul>\n<p>A continuaci\u00f3n se muestran las soluciones.<br \/>\n<!--more--><\/p>\n<p><a name=\"ej1\"><\/a><\/p>\n<h3>1. Base de datos de actividades<\/h3>\n<p>Las bases de datos sobre actividades de personas pueden representarse mediante listas de elementos de la forma (a,b,c,d), donde a es el nombre de la persona, b su actividad, c su fecha de nacimiento y d la de su fallecimiento. Un ejemplo es la siguiente que usaremos a lo largo de este ejercicio,<\/p>\n<pre lang=\"text\">\n   personas :: [(String,String,Int,Int)]\n   personas = [(\"Cervantes\",\"Literatura\",1547,1616),\n               (\"Velazquez\",\"Pintura\",1599,1660),\n               (\"Picasso\",\"Pintura\",1881,1973),\n               (\"Beethoven\",\"Musica\",1770,1823),\n               (\"Poincare\",\"Ciencia\",1854,1912),\n               (\"Quevedo\",\"Literatura\",1580,1654),\n               (\"Goya\",\"Pintura\",1746,1828),\n               (\"Einstein\",\"Ciencia\",1879,1955),\n               (\"Mozart\",\"Musica\",1756,1791),\n               (\"Botticelli\",\"Pintura\",1445,1510),\n               (\"Borromini\",\"Arquitectura\",1599,1667),\n               (\"Bach\",\"Musica\",1685,1750)]\n<\/pre>\n<p>Definir las funciones<\/p>\n<pre lang=\"text\">\n   nombres   :: [(String,String,Int,Int)] -> [String]\n   musicos   :: [(String,String,Int,Int)] -> [String]\n   seleccion :: [(String,String,Int,Int)] -> String -> [String]\n   musicos'  :: [(String,String,Int,Int)] -> [String]\n   vivas     :: [(String,String,Int,Int)] -> Int -> [String]\n<\/pre>\n<p>tales que<\/p>\n<ul>\n<li><code>nombres bd<\/code> es la lista de los nombres de las personas de la base de datos <code>bd<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     \u03bb> nombres personas\n     [\"Cervantes\",\"Velazquez\",\"Picasso\",\"Beethoven\",\"Poincare\",\n      \"Quevedo\",\"Goya\",\"Einstein\",\"Mozart\",\"Botticelli\",\"Borromini\",\n      \"Bach\"]\n<\/pre>\n<ul>\n<li><code>musicos bd<\/code> es la lista de los nombres de los m\u00fasicos de la base de datos <code>bd<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     musicos personas  ==  [\"Beethoven\",\"Mozart\",\"Bach\"]\n<\/pre>\n<ul>\n<li><code>seleccion bd m<\/code> es la lista de los nombres de las personas de la base de datos <code>bd<\/code> cuya actividad es <code>m<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     \u03bb> seleccion personas \"Pintura\"\n     [\"Velazquez\",\"Picasso\",\"Goya\",\"Botticelli\"]\n     \u03bb> seleccion personas \"Musica\"\n     [\"Beethoven\",\"Mozart\",\"Bach\"]\n<\/pre>\n<ul>\n<li><code>musicos' bd<\/code> es la lista de los nombres de los m\u00fasicos de la base de datos <code>bd<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     musicos' personas  ==  [\"Beethoven\",\"Mozart\",\"Bach\"]\n<\/pre>\n<ul>\n<li><code>vivas bd a<\/code> es la lista de los nombres de las personas de la base de datos <code>bd<\/code> que estaban vivas en el a\u00f1o <code>a<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     \u03bb> vivas personas 1600\n     [\"Cervantes\",\"Velazquez\",\"Quevedo\",\"Borromini\"]\n<\/pre>\n<h4>Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\npersonas :: [(String,String,Int,Int)]\npersonas = [(\"Cervantes\",\"Literatura\",1547,1616),\n            (\"Velazquez\",\"Pintura\",1599,1660),\n            (\"Picasso\",\"Pintura\",1881,1973),\n            (\"Beethoven\",\"Musica\",1770,1823),\n            (\"Poincare\",\"Ciencia\",1854,1912),\n            (\"Quevedo\",\"Literatura\",1580,1654),\n            (\"Goya\",\"Pintura\",1746,1828),\n            (\"Einstein\",\"Ciencia\",1879,1955),\n            (\"Mozart\",\"Musica\",1756,1791),\n            (\"Botticelli\",\"Pintura\",1445,1510),\n            (\"Borromini\",\"Arquitectura\",1599,1667),\n            (\"Bach\",\"Musica\",1685,1750)]\n\nnombres :: [(String,String,Int,Int)] -> [String]\nnombres bd = [x | (x,_,_,_) <- bd]\n\nmusicos :: [(String,String,Int,Int)] -> [String]\nmusicos bd = [x | (x,\"Musica\",_,_) <- bd]\n\nseleccion :: [(String,String,Int,Int)] -> String -> [String]\nseleccion bd m = [ x | (x,m',_,_) <- bd, m == m' ]\n\nmusicos' :: [(String,String,Int,Int)] -> [String]\nmusicos' bd = seleccion bd \"Musica\"\n\nvivas :: [(String,String,Int,Int)] -> Int -> [String]\nvivas bd a = [x | (x,_,a1,a2) <- bd, a1 <= a, a <= a2]\n<\/pre>\n<h4>Soluciones en Python<\/h4>\n<pre lang=\"python\">\nBD = list[tuple[str, str, int, int]]\n\npersonas: BD = [\n    (\"Cervantes\", \"Literatura\", 1547, 1616),\n    (\"Velazquez\", \"Pintura\", 1599, 1660),\n    (\"Picasso\", \"Pintura\", 1881, 1973),\n    (\"Beethoven\", \"Musica\", 1770, 1823),\n    (\"Poincare\", \"Ciencia\", 1854, 1912),\n    (\"Quevedo\", \"Literatura\", 1580, 1654),\n    (\"Goya\", \"Pintura\", 1746, 1828),\n    (\"Einstein\", \"Ciencia\", 1879, 1955),\n    (\"Mozart\", \"Musica\", 1756, 1791),\n    (\"Botticelli\", \"Pintura\", 1445, 1510),\n    (\"Borromini\", \"Arquitectura\", 1599, 1667),\n    (\"Bach\", \"Musica\", 1685, 1750)]\n\ndef nombres(bd: BD) -> list[str]:\n    return [p[0] for p in bd]\n\ndef musicos(bd: BD) -> list[str]:\n    return [p[0] for p in bd if p[1] == \"Musica\"]\n\ndef seleccion(bd: BD, m: str) -> list[str]:\n    return [p[0] for p in bd if p[1] == m]\n\ndef musicos2(bd: BD) -> list[str]:\n    return seleccion(bd, \"Musica\")\n\ndef vivas(bd: BD, a: int) -> list[str]:\n    return [p[0] for p in bd if p[2] <= a <= p[3]]\n<\/pre>\n<p><a name=\"ej2\"><\/a><\/p>\n<h3>2. Potencia entera<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   potencia :: Integer -> Integer -> Integer\n<\/pre>\n<p>tal que <code>potencia x n<\/code> es <code>x<\/code> elevado al n\u00famero natural <code>n<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   potencia 2 3  ==  8\n<\/pre>\n<h4>Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nimport Data.List (foldl')\nimport Control.Arrow ((***))\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\npotencia1 :: Integer -> Integer -> Integer\npotencia1 _ 0 = 1\npotencia1 m n = m * potencia1 m (n-1)\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\npotencia2 :: Integer -> Integer -> Integer\npotencia2 m = aux\n  where aux 0 = 1\n        aux n = m * aux (n-1)\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\npotencia3 :: Integer -> Integer -> Integer\npotencia3 m = aux 1\n  where aux r 0 = r\n        aux r n = aux (r*m) (n-1)\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\npotencia4 :: Integer -> Integer -> Integer\npotencia4 m = aux 1\n  where aux r 0 = r\n        aux r n = (aux $! (r*m)) $! (n-1)\n\n-- 5\u00aa soluci\u00f3n\n-- ===========\n\npotencia5 :: Integer -> Integer -> Integer\npotencia5 m n = product [m | _ <- [1..n]]\n\n-- 6\u00aa soluci\u00f3n\n-- ===========\n\npotencia6 :: Integer -> Integer -> Integer\npotencia6 m n = foldl' (*) 1 [m | _ <- [1..n]]\n\n-- 7\u00aa soluci\u00f3n\n-- ===========\n\npotencia7 :: Integer -> Integer -> Integer\npotencia7 m n =\n  fst (until (\\ (_,k) -> k == n)\n             (\\ (r,k) -> (r*m, k+1))\n             (1,0))\n\n-- 8\u00aa soluci\u00f3n\n-- ===========\n\npotencia8 :: Integer -> Integer -> Integer\npotencia8 m n =\n  fst (until ((== n) . snd)\n             ((m *) *** (1 +))\n             (1,0))\n\n-- 9\u00aa soluci\u00f3n\n-- ===========\n\npotencia9 :: Integer -> Integer -> Integer\npotencia9 m n = m^n\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_potencia :: Integer -> NonNegative Integer -> Bool\nprop_potencia m (NonNegative n) =\n  all (== potencia1 m n)\n      [potencia2 m n,\n       potencia3 m n,\n       potencia4 m n,\n       potencia5 m n,\n       potencia6 m n,\n       potencia7 m n,\n       potencia8 m n,\n       potencia9 m n]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_potencia\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> length (show (potencia1 2 (2*10^5)))\n--    60206\n--    (2.97 secs, 2,602,252,408 bytes)\n--    \u03bb> length (show (potencia2 2 (2*10^5)))\n--    60206\n--    (2.63 secs, 2,624,652,624 bytes)\n--    \u03bb> length (show (potencia3 2 (2*10^5)))\n--    60206\n--    (3.41 secs, 2,619,606,368 bytes)\n--    \u03bb> length (show (potencia4 2 (2*10^5)))\n--    60206\n--    (0.64 secs, 2,636,888,928 bytes)\n--    \u03bb> length (show (potencia5 2 (2*10^5)))\n--    60206\n--    (2.47 secs, 2,597,108,000 bytes)\n--    \u03bb> length (show (potencia6 2 (2*10^5)))\n--    60206\n--    (0.35 secs, 2,582,488,824 bytes)\n--    \u03bb> length (show (potencia7 2 (2*10^5)))\n--    60206\n--    (2.48 secs, 2,616,406,272 bytes)\n--    \u03bb> length (show (potencia8 2 (2*10^5)))\n--    60206\n--    (2.40 secs, 2,608,652,736 bytes)\n--    \u03bb> length (show (potencia9 2 (2*10^5)))\n--    60206\n--    (0.01 secs, 4,212,968 bytes)\n--\n--    \u03bb> length (show (potencia4 2 (10^6)))\n--    301030\n--    (10.39 secs, 63,963,999,656 bytes)\n--    \u03bb> length (show (potencia6 2 (10^6)))\n--    301030\n--    (8.90 secs, 63,691,999,552 bytes)\n--    \u03bb> length (show (potencia9 2 (10^6)))\n--    301030\n--    (0.04 secs, 19,362,032 bytes)\n<\/pre>\n<h4>Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom functools import reduce\nfrom operator import mul\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\ndef potencia1(m: int, n: int) -> int:\n    if n == 0:\n        return 1\n    return m * potencia1(m, n-1)\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef potencia2(m: int, n: int) -> int:\n    def aux(k: int) -> int:\n        if k == 0:\n            return 1\n        return m * aux(k-1)\n    return aux(n)\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef potencia3(m: int, n: int) -> int:\n    def aux(r: int, k: int) -> int:\n        if k == 0:\n            return r\n        return aux(r*m, k-1)\n    return aux(1, n)\n\n# 4\u00aa soluci\u00f3n\n# ===========\n\n# producto(xs) es el producto de los elementos de xs. Por ejemplo,\n#    producto([2, 3, 5])  ==  30\ndef producto(xs: list[int]) -> int:\n    return reduce(mul, xs, 1)\n\ndef potencia4(m: int, n: int) -> int:\n    return producto([m]*n)\n\n# 5\u00aa soluci\u00f3n\n# ===========\n\ndef potencia5(m: int, n: int) -> int:\n    r = 1\n    for _ in range(0, n):\n        r = r * m\n    return r\n\n# 6\u00aa soluci\u00f3n\n# ===========\n\ndef potencia6(m: int, n: int) -> int:\n    return m**n\n\n# Comprobaci\u00f3n de equivalencia\n# ============================\n\n# La propiedad es\n@given(st.integers(),\n       st.integers(min_value=0, max_value=100))\ndef test_potencia(m: int, n: int) -> None:\n    r = potencia1(m, n)\n    assert potencia2(m, n) == r\n    assert potencia3(m, n) == r\n    assert potencia4(m, n) == r\n    assert potencia5(m, n) == r\n    assert potencia6(m, n) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q potencia_entera.py\n#    1 passed in 0.17s\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('potencia1(2, 2*10**4)')\n#    0.01 segundos\n#    >>> tiempo('potencia2(2, 2*10**4)')\n#    0.01 segundos\n#    >>> tiempo('potencia3(2, 2*10**4)')\n#    0.02 segundos\n#    >>> tiempo('potencia4(2, 2*10**4)')\n#    0.01 segundos\n#    >>> tiempo('potencia5(2, 2*10**4)')\n#    0.01 segundos\n#    >>> tiempo('potencia6(2, 2*10**4)')\n#    0.00 segundos\n#\n#    >>> tiempo('potencia4(2, 5*10**5)')\n#    2.87 segundos\n#    >>> tiempo('potencia5(2, 5*10**5)')\n#    3.17 segundos\n#    >>> tiempo('potencia6(2, 5*10**5)')\n#    0.00 segundos\n<\/pre>\n<p><a name=\"ej3\"><\/a><\/p>\n<h3>3. Algoritmo de Euclides del mcd<\/h3>\n<p>Dados dos n\u00fameros naturales, a y b, es posible calcular su m\u00e1ximo com\u00fan divisor mediante el Algoritmo de Euclides. Este algoritmo se puede resumir en la siguiente f\u00f3rmula:<\/p>\n<pre lang=\"text\">\n   mcd(a,b) = a,                   si b = 0\n            = mcd (b, a m\u00f3dulo b), si b > 0\n<\/pre>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   mcd :: Integer -> Integer -> Integer\n<\/pre>\n<p>tal que <code>mcd a b<\/code> es el m\u00e1ximo com\u00fan divisor de <code>a<\/code> y <code>b<\/code> calculado mediante el algoritmo de Euclides. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   mcd 30 45  ==  15\n   mcd 45 30  ==  15\n<\/pre>\n<p>Comprobar con QuickCheck que el m\u00e1ximo com\u00fan divisor de dos n\u00fameros <code>a<\/code> y <code>b<\/code> (ambos mayores que 0) es siempre mayor o igual que 1 y adem\u00e1s es menor o igual que el menor de los n\u00fameros <code>a<\/code>  y <code>b<\/code>.<\/p>\n<h4>Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nimport Test.QuickCheck\n\nmcd :: Integer -> Integer -> Integer\nmcd a 0 = a\nmcd a b = mcd b (a `mod` b)\n\n-- La propiedad es\nprop_mcd :: Positive Integer -> Positive Integer -> Bool\nprop_mcd (Positive a) (Positive b) =\n  m >= 1 && m <= min a b\n  where m = mcd a b\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_mcd\n--    OK, passed 100 tests.\n<\/pre>\n<h4>Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\ndef mcd(a: int, b: int) -> int:\n    if b == 0:\n        return a\n    return mcd(b, a % b)\n\n# -- La propiedad es\n@given(st.integers(min_value=1, max_value=1000),\n       st.integers(min_value=1, max_value=1000))\ndef test_mcd(a: int, b: int) -> None:\n    assert 1 <= mcd(a, b) <= min(a, b)\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q algoritmo_de_Euclides_del_mcd.py\n#    1 passed in 0.22s\n<\/pre>\n<p><a name=\"ej4\"><\/a><\/p>\n<h3>4. D\u00edgitos de un n\u00famero<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   digitos :: Integer -> [Int]\n<\/pre>\n<p>tal que <code>digitos n<\/code> es la lista de los d\u00edgitos del n\u00famero <code>n<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   digitos 320274  ==  [3,2,0,2,7,4]\n<\/pre>\n<h4>Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nimport Data.Char (digitToInt)\nimport qualified Data.Digits as D (digits)\nimport qualified Data.FastDigits as FD (digits)\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\ndigitos1 :: Integer -> [Int]\ndigitos1 n = map fromInteger (aux n)\n  where aux :: Integer -> [Integer]\n        aux m\n          | m < 10    = [m]\n          | otherwise = aux (m `div` 10) ++ [m `rem` 10]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\ndigitos2 :: Integer -> [Int]\ndigitos2 n = map fromInteger (reverse (aux n))\n  where aux :: Integer -> [Integer]\n        aux m\n          | m < 10    = [m]\n          | otherwise = (m `rem` 10) : aux (m `div` 10)\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\ndigitos3 :: Integer -> [Int]\ndigitos3 n = map fromInteger (aux [] n)\n  where aux :: [Integer] -> Integer -> [Integer]\n        aux ds m\n          | m < 10    = m : ds\n          | otherwise = aux (m `rem` 10 : ds) (m `div` 10)\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\ndigitos4 :: Integer -> [Int]\ndigitos4 n = [read [x] | x <- show n]\n\n-- 5\u00aa soluci\u00f3n\n-- ===========\n\ndigitos5 :: Integer -> [Int]\ndigitos5 n = map (\\ x -> read [x]) (show n)\n\n-- 6\u00aa soluci\u00f3n\n-- ===========\n\ndigitos6 :: Integer -> [Int]\ndigitos6 = map (read . return) . show\n\n-- 7\u00aa soluci\u00f3n\n-- ===========\n\ndigitos7 :: Integer -> [Int]\ndigitos7 n = map digitToInt (show n)\n\n-- 8\u00aa soluci\u00f3n\n-- ===========\n\ndigitos8 :: Integer -> [Int]\ndigitos8 = map digitToInt . show\n\n-- 9\u00aa soluci\u00f3n\n-- ===========\n\ndigitos9 :: Integer -> [Int]\ndigitos9 0 = [0]\ndigitos9 n = map fromInteger (D.digits 10 n)\n\n-- 10\u00aa soluci\u00f3n\n-- ===========\n\ndigitos10 :: Integer -> [Int]\ndigitos10 0 = [0]\ndigitos10 n = reverse (FD.digits 10 n)\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_digitos :: NonNegative Integer -> Bool\nprop_digitos (NonNegative n) =\n  all (== digitos1 n)\n      [digitos2 n,\n       digitos3 n,\n       digitos4 n,\n       digitos5 n,\n       digitos6 n,\n       digitos7 n,\n       digitos8 n,\n       digitos9 n,\n       digitos10 n]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_digitos\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> n = product [1..5000]\n--    \u03bb> length (digitos1 n)\n--    16326\n--    (3.00 secs, 11,701,450,912 bytes)\n--    \u03bb> length (digitos2 n)\n--    16326\n--    (0.13 secs, 83,393,816 bytes)\n--    \u03bb> length (digitos3 n)\n--    16326\n--    (0.11 secs, 83,132,552 bytes)\n--    \u03bb> length (digitos4 n)\n--    16326\n--    (0.01 secs, 23,054,920 bytes)\n--    \u03bb> length (digitos5 n)\n--    16326\n--    (0.01 secs, 22,663,088 bytes)\n--    \u03bb> length (digitos6 n)\n--    16326\n--    (0.06 secs, 22,663,224 bytes)\n--    \u03bb> length (digitos7 n)\n--    16326\n--    (0.01 secs, 22,663,064 bytes)\n--    \u03bb> length (digitos8 n)\n--    16326\n--    (0.03 secs, 22,663,192 bytes)\n--    \u03bb> length (digitos9 n)\n--    16326\n--    (0.05 secs, 82,609,944 bytes)\n--    \u03bb> length (digitos10 n)\n--    16326\n--    (0.01 secs, 26,295,416 bytes)\n--\n--    \u03bb> n = product [1..5*10^4]\n--    \u03bb> length (digitos2 n)\n--    213237\n--    (10.17 secs, 12,143,633,056 bytes)\n--    \u03bb> length (digitos3 n)\n--    213237\n--    (10.54 secs, 12,140,221,216 bytes)\n--    \u03bb> length (digitos4 n)\n--    213237\n--    (1.29 secs, 2,638,199,328 bytes)\n--    \u03bb> length (digitos5 n)\n--    213237\n--    (2.48 secs, 2,633,081,632 bytes)\n--    \u03bb> length (digitos6 n)\n--    213237\n--    (2.59 secs, 2,633,081,600 bytes)\n--    \u03bb> length (digitos7 n)\n--    213237\n--    (2.55 secs, 2,633,081,608 bytes)\n--    \u03bb> length (digitos8 n)\n--    213237\n--    (2.49 secs, 2,633,081,600 bytes)\n--    \u03bb> length (digitos9 n)\n--    213237\n--    (7.07 secs, 12,133,397,456 bytes)\n--    \u03bb> length (digitos10 n)\n--    213237\n--    (2.47 secs, 2,725,182,064 bytes)\n<\/pre>\n<h4>Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom math import factorial\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\nfrom sympy.ntheory.digits import digits\n\nsetrecursionlimit(10**6)\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\ndef digitos1(n: int) -> list[int]:\n    if n < 10:\n        return [n]\n    return digitos1(n \/\/ 10) + [n % 10]\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef digitos2(n: int) -> list[int]:\n    return [int(x) for x in str(n)]\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef digitos3(n: int) -> list[int]:\n    r: list[int] = []\n    for x in str(n):\n        r.append(int(x))\n    return r\n\n# 4\u00aa soluci\u00f3n\n# ===========\n\ndef digitos4(n: int) -> list[int]:\n    return list(map(int, list(str(n))))\n\n# 5\u00aa soluci\u00f3n\n# ===========\n\ndef digitos5(n: int) -> list[int]:\n    r: list[int] = []\n    while n > 0:\n        r = [n % 10] + r\n        n = n \/\/ 10\n    return r\n\n# 6\u00aa soluci\u00f3n\n# ===========\n\ndef digitos6(n: int) -> list[int]:\n    r: list[int] = []\n    while n > 0:\n        r.append(n % 10)\n        n = n \/\/ 10\n    return list(reversed(r))\n\n# 7\u00aa soluci\u00f3n\n# ===========\n\ndef digitos7(n: int) -> list[int]:\n    return digits(n)[1:]\n\n# Comprobaci\u00f3n de equivalencia\n# ============================\n\n# La propiedad es\n@given(st.integers(min_value=1))\ndef test_digitos(n: int) -> None:\n    r = digitos1(n)\n    assert digitos2(n) == r\n    assert digitos3(n) == r\n    assert digitos4(n) == r\n    assert digitos5(n) == r\n    assert digitos6(n) == r\n    assert digitos7(n) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q digitos_de_un_numero.py\n#    1 passed in 0.49s\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(ex: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(ex, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('digitos1(factorial(6000))')\n#    0.58 segundos\n#    >>> tiempo('digitos2(factorial(6000))')\n#    0.01 segundos\n#    >>> tiempo('digitos3(factorial(6000))')\n#    0.01 segundos\n#    >>> tiempo('digitos4(factorial(6000))')\n#    0.01 segundos\n#    >>> tiempo('digitos5(factorial(6000))')\n#    0.60 segundos\n#    >>> tiempo('digitos6(factorial(6000))')\n#    0.17 segundos\n#    >>> tiempo('digitos7(factorial(6000))')\n#    0.10 segundos\n#\n#    >>> tiempo('digitos2(factorial(2*10**4))')\n#    0.10 segundos\n#    >>> tiempo('digitos3(factorial(2*10**4))')\n#    0.10 segundos\n#    >>> tiempo('digitos4(factorial(2*10**4))')\n#    0.09 segundos\n#    >>> tiempo('digitos6(factorial(2*10**4))')\n#    2.33 segundos\n#    >>> tiempo('digitos7(factorial(2*10**4))')\n#    1.18 segundos\n#\n#    >>> tiempo('digitos2(factorial(10**5))')\n#    3.53 segundos\n#    >>> tiempo('digitos3(factorial(10**5))')\n#    3.22 segundos\n#    >>> tiempo('digitos4(factorial(10**5))')\n#    3.02 segundos\n<\/pre>\n<p><a name=\"ej5\"><\/a><\/p>\n<h3>5. Suma de los d\u00edgitos de un n\u00famero<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   sumaDigitos :: Integer -> Integer\n<\/pre>\n<p>tal que <code>sumaDigitos n<\/code> es la suma de los d\u00edgitos de <code>n<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   sumaDigitos 3     ==  3\n   sumaDigitos 2454  == 15\n   sumaDigitos 20045 == 11\n<\/pre>\n<h4>Soluciones en Haskell<\/h4>\n<pre lang=\"haskell\">\nimport Data.List (foldl')\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nsumaDigitos1 :: Integer -> Integer\nsumaDigitos1 n = sum (digitos n)\n\n-- (digitos n) es la lista de los d\u00edgitos del n\u00famero n. Por ejemplo,\n--    digitos 320274  ==  [3,2,0,2,7,4]\ndigitos :: Integer -> [Integer]\ndigitos n = [read [x] | x <- show n]\n\n-- Nota. En lugar de la definici\u00f3n anterior de digitos se puede usar\n-- cualquiera del ejercicio \"D\u00edgitos de un n\u00famero\" https:\/\/bit.ly\/3Tkhc2T\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nsumaDigitos2 :: Integer -> Integer\nsumaDigitos2 n = foldl' (+) 0 (digitos n)\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nsumaDigitos3 :: Integer -> Integer\nsumaDigitos3 n\n  | n < 10    = n\n  | otherwise = n `rem` 10 + sumaDigitos3 (n `div` 10)\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nsumaDigitos4 :: Integer -> Integer\nsumaDigitos4 = aux 0\n  where aux r n\n          | n < 10    = r + n\n          | otherwise = aux (r + n `rem` 10) (n `div` 10)\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_sumaDigitos :: NonNegative Integer -> Bool\nprop_sumaDigitos (NonNegative n) =\n  all (== sumaDigitos1 n)\n      [sumaDigitos2 n,\n       sumaDigitos3 n,\n       sumaDigitos4 n]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_sumaDigitos\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> sumaDigitos1 (product [1..2*10^4])\n--    325494\n--    (0.64 secs, 665,965,832 bytes)\n--    \u03bb> sumaDigitos2 (product [1..2*10^4])\n--    325494\n--    (0.41 secs, 660,579,064 bytes)\n--    \u03bb> sumaDigitos3 (product [1..2*10^4])\n--    325494\n--    (1.58 secs, 1,647,082,224 bytes)\n--    \u03bb> sumaDigitos4 (product [1..2*10^4])\n--    325494\n--    (1.72 secs, 1,662,177,792 bytes)\n--\n--    \u03bb> sumaDigitos1 (product [1..5*10^4])\n--    903555\n--    (2.51 secs, 3,411,722,136 bytes)\n--    \u03bb> sumaDigitos2 (product [1..5*10^4])\n--    903555\n--    (2.30 secs, 3,396,802,856 bytes)\n<\/pre>\n<h4>Soluciones en Python<\/h4>\n<pre lang=\"python\">\nfrom functools import reduce\nfrom math import factorial\nfrom operator import add\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\n# digitos(n) es la lista de los d\u00edgitos del n\u00famero n. Por ejemplo,\n#    digitos(320274)  ==  [3, 2, 0, 2, 7, 4]\ndef digitos(n: int) -> list[int]:\n    return list(map(int, list(str(n))))\n\ndef sumaDigitos1(n: int) -> int:\n    return sum(digitos(n))\n\n# Nota. En lugar de la definici\u00f3n anterior de digitos se puede usar\n# cualquiera del ejercicio \"D\u00edgitos de un n\u00famero\" https:\/\/bit.ly\/3Tkhc2T\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef sumaDigitos2(n: int) -> int:\n    return reduce(add, digitos(n))\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef sumaDigitos3(n: int) -> int:\n    if n < 10:\n        return n\n    return n % 10 + sumaDigitos3(n \/\/ 10)\n\n# 4\u00aa soluci\u00f3n\n# ===========\n\ndef sumaDigitos4(n: int) -> int:\n    def aux(r: int, m: int) -> int:\n        if m < 10:\n            return r + m\n        return aux(r + m % 10, m \/\/ 10)\n    return aux(0, n)\n\n# 5\u00aa soluci\u00f3n\n# ===========\n\ndef sumaDigitos5(n: int) -> int:\n    r = 0\n    for x in digitos(n):\n        r = r + x\n    return r\n\n# Comprobaci\u00f3n de equivalencia\n# ============================\n\n# La propiedad es\n@given(st.integers(min_value=0, max_value=1000))\ndef test_sumaDigitos(n: int) -> None:\n    r = sumaDigitos1(n)\n    assert sumaDigitos2(n) == r\n    assert sumaDigitos3(n) == r\n    assert sumaDigitos4(n) == r\n    assert sumaDigitos5(n) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q suma_de_los_digitos_de_un_numero.py\n#    1 passed in 0.35s\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('sumaDigitos1(factorial(6*10**3))')\n#    0.01 segundos\n#    >>> tiempo('sumaDigitos2(factorial(6*10**3))')\n#    0.01 segundos\n#    >>> tiempo('sumaDigitos3(factorial(6*10**3))')\n#    0.13 segundos\n#    >>> tiempo('sumaDigitos4(factorial(6*10**3))')\n#    0.13 segundos\n#    >>> tiempo('sumaDigitos5(factorial(6*10**3))')\n#    0.01 segundos\n#\n#    >>> tiempo('sumaDigitos1(factorial(10**5))')\n#    2.20 segundos\n#    >>> tiempo('sumaDigitos2(factorial(10**5))')\n#    2.22 segundos\n#    >>> tiempo('sumaDigitos5(factorial(10**5))')\n#    2.19 segundos\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Esta semana he publicado en Exercitium las soluciones de los siguientes problemas: 1. Base de datos de actividades 2. Potencia entera 3. Algoritmo de Euclides del mcd 4. D\u00edgitos de un n\u00famero 5. Suma de los d\u00edgitos de un n\u00famero A continuaci\u00f3n se muestran las soluciones.<\/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":[337],"tags":[],"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\/7823"}],"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=7823"}],"version-history":[{"count":8,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/7823\/revisions"}],"predecessor-version":[{"id":7831,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/7823\/revisions\/7831"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/media?parent=7823"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/categories?post=7823"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/tags?post=7823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}