import Data.List (genericLength, permutations, foldl')
import Test.QuickCheck
import Graphics.Gnuplot.Simple
-- 1ª definición de numeroMedio
-- ============================
numeroMedio :: Integer -> Bool
numeroMedio n =
n == media (map digitosAnumero (permutations (digitos n)))
-- (digitos n) es la lista de los dígitos de n. Por ejemplo,
-- digitos 425 == [4,2,5]
digitos :: Integer -> [Integer]
digitos n =
[read [c] | c <- show n]
-- (digitosAnumero xs) es el número cuya lista de dígitos es xs. Por
-- ejemplo,
-- digitosAnumero [4,2,5] == 425
-- 1ª definición de digitosAnumero
digitosAnumero1 :: [Integer] -> Integer
digitosAnumero1 = aux . reverse
where aux [] = 0
aux (x:xs) = x + 10 * aux xs
-- 1ª definición de digitosAnumero
digitosAnumero2 :: [Integer] -> Integer
digitosAnumero2 = foldl' (\x y -> 10*x+y) 0
-- Comparación de eficiencia de definiciones de digitosAnumero
-- λ> length (show (digitosAnumero1 (replicate (10^5) 5)))
-- 100000
-- (5.07 secs, 4,317,349,968 bytes)
-- λ> length (show (digitosAnumero2 (replicate (10^5) 5)))
-- 100000
-- (0.67 secs, 4,288,054,592 bytes)
-- Se usará la 2ª definición de digitosAnumero
digitosAnumero :: [Integer] -> Integer
digitosAnumero = digitosAnumero2
-- (media xs) es la media aritmética de la lista xs (se supone que su
-- valor es entero). Por ejemplo,
-- media [370,730,73,703,37,307] == 370
media :: [Integer] -> Integer
media xs = sum xs `div` genericLength xs
-- 2ª definición de numeroMedio
-- ============================
numeroMedio2 :: Integer -> Bool
numeroMedio2 n =
(10^k-1)*s == 9*k*n
where xs = digitos n
k = genericLength xs
s = sum xs
-- Equivalencia de las definiciones de numeroMedio
-- ===============================================
-- La propiedad es
prop_numeroMedio :: Positive Integer -> Bool
prop_numeroMedio (Positive n) =
numeroMedio n == numeroMedio2 n
-- La comprobación es
-- λ> quickCheck prop_numeroMedio
-- +++ OK, passed 100 tests.
-- Comparación de eficiencia de las definiciones de numeroMedio
-- ============================================================
-- λ> filter numeroMedio [10000..20000]
-- [11111]
-- (1.74 secs, 1,500,858,904 bytes)
-- λ> filter numeroMedio2 [10000..20000]
-- [11111]
-- (0.11 secs, 213,060,784 bytes)
-- Definición de densidadesNumeroMedio
-- ===================================
densidadesNumeroMedio :: [Double]
densidadesNumeroMedio =
[genericLength (filter numeroMedio2 [1..n]) / fromIntegral n | n <- [1..]]
-- Definición de graficaDensidadNumeroMedio
-- ========================================
graficaDensidadNumeroMedio :: Int -> IO ()
graficaDensidadNumeroMedio n =
plotList [ Title ("graficaDensidadNumeroMedio")
, Key Nothing
-- , PNG ("Numero_medio_" ++ show n ++ ".png" )
, XRange (1, fromIntegral n)]
(take n densidadesNumeroMedio)