Diferencia entre revisiones de «Relación 10»
De Informática de 1º de Matemáticas [Curso 2021-22, Grupo 3]
(Página creada con «<source lang='haskell'> -- I1M 2021-22 -- Propiedades del número 2021. -- Departamento de Ciencias de la Computación e I.A. -- Universidad de Sevilla -- =================…») |
|||
Línea 37: | Línea 37: | ||
-- sumaDominoPrimos 200 == 8253 | -- sumaDominoPrimos 200 == 8253 | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
sumaDominoPrimos :: Integer -> Integer | sumaDominoPrimos :: Integer -> Integer | ||
sumaDominoPrimos n = | sumaDominoPrimos n = sum (map (\(x,y) -> x+y) (aux (primosMenores n))) | ||
where aux [] = [] | |||
aux [x] = [] | |||
aux (x:y:xs) = [(x,y)] ++ aux (y:xs) | |||
primo :: Integer -> Bool | |||
primo n | n<=0 = False | |||
| n==1 = True | |||
| otherwise = and [mod n x /= 0 | x <- [2..(n-1)]] | |||
primosMenores :: Integer -> [Integer] | |||
primosMenores n = [x | x <- [2..n], primo x] | |||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
Línea 50: | Línea 64: | ||
-- 1205,1349,1501,1663,1835,2021,2219] | -- 1205,1349,1501,1663,1835,2021,2219] | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
sucSumaDominoPrimos :: [Integer] | sucSumaDominoPrimos :: [Integer] | ||
sucSumaDominoPrimos = | sucSumaDominoPrimos = [5] ++ aux2 (map (\(x,y) -> x+y) (aux primosInf)) 2 | ||
where aux [] = [] | |||
aux [x] = [] | |||
aux (x:y:xs) = [(x,y)] ++ aux (y:xs) | |||
aux2 xs n = [sum (take n xs)] ++ aux2 xs (n+1) | |||
primosInf :: [Integer] | |||
primosInf = [x | x <- [2..], primo x] | |||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
Línea 62: | Línea 85: | ||
-- esSumaDominoPrimos 1234509 == False | -- esSumaDominoPrimos 1234509 == False | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
esSumaDominoPrimos :: Integer -> Bool | esSumaDominoPrimos :: Integer -> Bool | ||
esSumaDominoPrimos n = | esSumaDominoPrimos n = head (dropWhile (<n) sucSumaDominoPrimos) == n | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
Línea 77: | Línea 102: | ||
-- sumSumaPrimos 52 == 5641 | -- sumSumaPrimos 52 == 5641 | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
sumSumaPrimos :: Int -> Integer | sumSumaPrimos :: Int -> Integer | ||
sumSumaPrimos n = | sumSumaPrimos n = toInteger n + sum (take n primosInf) | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
Línea 89: | Línea 116: | ||
-- esSumSumaPrimos 120 == False | -- esSumSumaPrimos 120 == False | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
esSumSumaPrimos :: Integer -> Bool | esSumSumaPrimos :: Integer -> Bool | ||
esSumSumaPrimos n = | esSumSumaPrimos n = head (dropWhile (<n) [sumSumaPrimos x | x <- [1.. ]]) == n | ||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
-- | -- ejercicio 3. Un número semiprimo es un número natural que es producto | ||
-- de dos números primos no necesariamente distintos. Por ejemplo, 26 es | -- de dos números primos no necesariamente distintos. Por ejemplo, 26 es | ||
-- semiprimo (porque 26 = 2×13) y 49 también lo es (porque 49 = 7×7). | -- semiprimo (porque 26 = 2×13) y 49 también lo es (porque 49 = 7×7). | ||
Línea 111: | Línea 140: | ||
-- semiprimos !! 580 == 2021 | -- semiprimos !! 580 == 2021 | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
esSemiprimo :: Integer -> Bool | esSemiprimo :: Integer -> Bool | ||
esSemiprimo n = | esSemiprimo n = head (dropWhile (<n) semiprimos) == n | ||
semiprimos :: [Integer] | semiprimos :: [Integer] | ||
semiprimos = | semiprimos = [x | x <- [4..],not (primo x), divisionDePrimos x] | ||
divisionDePrimos :: Integer -> Bool | |||
divisionDePrimos n = or [primo (div n y) | y <- (primosMenores n), div n y * y == n] | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 140: | Línea 174: | ||
-- sucBlum !! 132 == 2021 | -- sucBlum !! 132 == 2021 | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
esBlum :: Integer -> Bool | esBlum :: Integer -> Bool | ||
esBlum n = | esBlum n = head (dropWhile (<n) sucBlum) == n | ||
sucBlum :: [Integer] | sucBlum :: [Integer] | ||
sucBlum = | sucBlum = [x | x <- [21..], not (primo x), divisionDePrimosBlum x] | ||
divisionDePrimosBlum :: Integer -> Bool | |||
divisionDePrimosBlum n = or [primo (div n y) | y <- (primosMenores n), (div n y) /= y, mod y 4 == 3, mod (div n y) 4 == 3, div n y * y == n] | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 164: | Línea 203: | ||
-- sucBrillante !! 130 == 2021 | -- sucBrillante !! 130 == 2021 | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
esBrillante :: Integer -> Bool | esBrillante :: Integer -> Bool | ||
esBrillante n = | esBrillante n = head (dropWhile (<n) sucBrillante) == n | ||
sucBrillante :: [Integer] | sucBrillante :: [Integer] | ||
sucBrillante = | sucBrillante = [x | x <- [4..], not (primo x), divisionDePrimosBrillante x] | ||
divisionDePrimosBrillante :: Integer -> Bool | |||
divisionDePrimosBrillante n = or [primo (div n y) | y <- (primosMenores n), numeroDigitos (div n y) == numeroDigitos y, div n y * y == n] | |||
numeroDigitos :: Integer -> Integer | |||
numeroDigitos n | n<10 = 1 | |||
| otherwise = numeroDigitos (div n 10) + 1 | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 193: | Línea 242: | ||
-- length (sucesionesConSuma 3000) == 7 | -- length (sucesionesConSuma 3000) == 7 | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
sucesionesConSuma :: Integer -> [(Integer,Integer)] | sucesionesConSuma :: Integer -> [(Integer,Integer)] | ||
sucesionesConSuma n = | sucesionesConSuma n = [(x,y) | x <- [1..n], y <- sucesion x n] | ||
sucesion :: Integer -> Integer -> [Integer] | |||
sucesion x n = [y | y<-[x..(n-1)], (div (y*(y+1)) 2) - (div (x*(x-1)) 2) == n] | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 209: | Línea 263: | ||
-- take 10 sucNoAmables == [1,2,4,8,16,32,64,128,256,512] | -- take 10 sucNoAmables == [1,2,4,8,16,32,64,128,256,512] | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
noAmable :: Integer -> Bool | noAmable :: Integer -> Bool | ||
noAmable n = | noAmable 1 = True | ||
noAmable n = if (div n 2) * 2 == n then noAmable (div n 2) else False | |||
sucNoAmables :: [Integer] | sucNoAmables :: [Integer] | ||
sucNoAmables = | sucNoAmables = [2^x| x<-[0..]] | ||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 220: | Línea 277: | ||
-- amable si y sólo si es potencia de 2. | -- amable si y sólo si es potencia de 2. | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
propNoAmable :: Integer -> Bool | propNoAmable :: Integer -> Bool | ||
propNoAmable n = | propNoAmable n = noAmable m == (head (dropWhile (<m) [2^x| x <-[0..]]) == m ) | ||
where m = 1 + abs n | |||
-- La comprobación es | |||
-- *Main> quickCheck propNoAmable | |||
-- +++ OK, passed 100 tests. | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 235: | Línea 299: | ||
-- esAritmetico 24 == False | -- esAritmetico 24 == False | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
esAritmetico :: Integer -> Bool | esAritmetico :: Integer -> Bool | ||
esAritmetico n = | esAritmetico n = (div (sum (divisores n)) (toInteger(length (divisores n)))) * (toInteger(length (divisores n))) == sum (divisores n) | ||
divisores :: Integer -> [Integer] | |||
divisores n = [x | x <- [1..n], mod n x == 0] | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 244: | Línea 313: | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
primosAritmeticos :: | -- Álvaro Galisteo: | ||
primosAritmeticos n = | |||
primosAritmeticos :: Int -> Bool | |||
primosAritmeticos n = all esAritmetico (take n (tail primosInf)) | |||
-- La comprobación es | -- La comprobación es | ||
-- *Main> quickCheck primosAritmeticos | |||
-- +++ OK, passed 100 tests. | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 260: | Línea 333: | ||
-- 4968,4969,4970,4971,4972,4973,4974] | -- 4968,4969,4970,4971,4972,4973,4974] | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
sucAritmeticosConsecutivos :: Int -> [Integer] | sucAritmeticosConsecutivos :: Int -> [Integer] | ||
sucAritmeticosConsecutivos n = | sucAritmeticosConsecutivos n = head (filter consecutivos (segmentosLongitud n sucAritmeticos)) | ||
sucAritmeticos :: [Integer] | |||
sucAritmeticos = filter esAritmetico [1..] | |||
segmentosLongitud :: Int -> [a] -> [[a]] | |||
segmentosLongitud n xs = map (take n) (tails xs) | |||
consecutivos :: [Integer] -> Bool | |||
consecutivos ns = all (==1) (zipWith (-) (tail ns) ns) | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 282: | Línea 367: | ||
-- prodInvPalindromo 1097 == False | -- prodInvPalindromo 1097 == False | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
masInvPalindromo :: Integer -> Bool | masInvPalindromo :: Integer -> Bool | ||
masInvPalindromo n = | masInvPalindromo n = digitos (n + numero(reverse(digitos n))) == reverse (digitos (n + numero(reverse(digitos n)))) | ||
prodInvPalindromo :: Integer -> Bool | prodInvPalindromo :: Integer -> Bool | ||
prodInvPalindromo n = | prodInvPalindromo n = digitos (n * numero(reverse(digitos n))) == reverse (digitos (n * numero(reverse(digitos n)))) | ||
digitos :: Integer -> [Integer] | |||
digitos n = [read [x] :: Integer | x <- (show n)] | |||
numero :: [Integer] -> Integer | |||
numero [x] = x | |||
numero xs = head xs * 10^(length xs - 1) + numero (tail xs) | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 293: | Línea 388: | ||
-- prodInvPalindromo es masInvPalindromo. | -- prodInvPalindromo es masInvPalindromo. | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
propInvPalindromo :: Integer -> Bool | propInvPalindromo :: Integer -> Bool | ||
propInvPalindromo n = | propInvPalindromo n = not (prodInvPalindromo m) || masInvPalindromo m | ||
where m = 1 + abs n | |||
-- La comprobación es | -- La comprobación es | ||
-- *Main> quickCheck propInvPalindromo | |||
-- +++ OK, passed 100 tests. | |||
-- -------------------------------------------------------------------- | -- -------------------------------------------------------------------- | ||
Línea 320: | Línea 420: | ||
-- head especiales == 2021 | -- head especiales == 2021 | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
-- Álvaro Galisteo: | |||
-- esConcatConsecutivos | -- esConcatConsecutivos | ||
Línea 325: | Línea 427: | ||
esConcatConsecutivos :: Integer -> Bool | esConcatConsecutivos :: Integer -> Bool | ||
esConcatConsecutivos n = | esConcatConsecutivos n | head( drop (div (length(digitos n)) 2) (digitos n)) == 0 = False | ||
| length (digitos n) == 1 = False | |||
| otherwise = numero (take (div (length(digitos n)) 2) (digitos n)) +1 == numero ( drop (div (length(digitos n)) 2) (digitos n)) | |||
-- esProdprimosConsecutivos | -- esProdprimosConsecutivos | ||
Línea 331: | Línea 435: | ||
esProdprimosConsecutivos :: Integer -> Bool | esProdprimosConsecutivos :: Integer -> Bool | ||
esProdprimosConsecutivos n = | esProdprimosConsecutivos n = esProdprimosConsecutivosAux n (divisores2 n) | ||
esProdprimosConsecutivosAux :: Integer -> [Integer] -> Bool | |||
esProdprimosConsecutivosAux n [] = False | |||
esProdprimosConsecutivosAux n (x:xs) = if elem (div n x) xs then [x, (div n x)] == take 2 (dropWhile (/=x) primosInf) else esProdprimosConsecutivosAux n xs | |||
divisores2 :: Integer -> [Integer] | |||
divisores2 n = [x | x <- [2..(n-1)], mod n x == 0, primo x] | |||
-- especiales | -- especiales | ||
Línea 337: | Línea 448: | ||
especiales :: [Integer] | especiales :: [Integer] | ||
especiales = | especiales = [x | x <- [1..], esConcatConsecutivos x, esProdprimosConsecutivos x] | ||
-- Primer número especial: | -- Primer número especial: | ||
-- *Main> head especiales | |||
-- 2021 | |||
</source> | </source> |
Revisión actual del 12:53 15 ene 2022
-- I1M 2021-22
-- Propiedades del número 2021.
-- Departamento de Ciencias de la Computación e I.A.
-- Universidad de Sevilla
-- =====================================================================
-- ---------------------------------------------------------------------
-- Introducción --
-- ---------------------------------------------------------------------
-- En esta relación se presentan ejercicios sobre propiedades del número
-- 2021.
--
-- NOTA: Siempre que se estime oportuno cambiar el tipo de salida de las
-- propiedades a Property
--
-- ---------------------------------------------------------------------
-- § Librerías auxiliares --
-- ---------------------------------------------------------------------
import Data.List
import Test.QuickCheck
-- ---------------------------------------------------------------------
-- Ejercicio 1.1. Consideramos todos los primos menores que 100:
-- 2, 3, 5, 7, 11, ..., 89, 97
-- y formamos los correspondientes pares de dominó:
-- (2,3), (3,5), (5,7), ..., (83,89), (89,97).
-- La suma de los números en todos los pares es 2021.
--
-- Definir la función
-- sumaDominoPrimos :: Integer -> Integer
-- tal que (sumaDominoPrimos n) es la suma de los números de los pares
-- de dominó formada a partir de los primos menores que n. Por ejemplo,
-- sumaDominoPrimos 100 == 2021
-- sumaDominoPrimos 200 == 8253
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
sumaDominoPrimos :: Integer -> Integer
sumaDominoPrimos n = sum (map (\(x,y) -> x+y) (aux (primosMenores n)))
where aux [] = []
aux [x] = []
aux (x:y:xs) = [(x,y)] ++ aux (y:xs)
primo :: Integer -> Bool
primo n | n<=0 = False
| n==1 = True
| otherwise = and [mod n x /= 0 | x <- [2..(n-1)]]
primosMenores :: Integer -> [Integer]
primosMenores n = [x | x <- [2..n], primo x]
-- ---------------------------------------------------------------------
-- Ejercicio 1.2. Definir la constante
-- sucSumaDominoPrimos :: [Integer]
-- tal que sucSumaDominoPrimos es la sucesión de los números que son
-- suma de pares de dominó formado con números primos. Por ejemplo,
-- λ> take 25 sucSumaDominoPrimos
-- [5,13,25,43,67,97,133,175,227,287,355,433,517,607,707,819,939,1067,
-- 1205,1349,1501,1663,1835,2021,2219]
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
sucSumaDominoPrimos :: [Integer]
sucSumaDominoPrimos = [5] ++ aux2 (map (\(x,y) -> x+y) (aux primosInf)) 2
where aux [] = []
aux [x] = []
aux (x:y:xs) = [(x,y)] ++ aux (y:xs)
aux2 xs n = [sum (take n xs)] ++ aux2 xs (n+1)
primosInf :: [Integer]
primosInf = [x | x <- [2..], primo x]
-- ---------------------------------------------------------------------
-- Ejercicio 1.3. Definir la sucesión
-- esSumaDominoPrimos :: Integer -> Bool
-- tal que (esSumaDominoPrimos n) se verifica si n es un número de la
-- sucesión anterior. Por ejemplo,
-- esSumaDominoPrimos 2021 == True
-- esSumaDominoPrimos 1234509 == False
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
esSumaDominoPrimos :: Integer -> Bool
esSumaDominoPrimos n = head (dropWhile (<n) sucSumaDominoPrimos) == n
-- ---------------------------------------------------------------------
-- Ejercicio 2.1. El número 2021 es la suma de 33 más la suma de los 33
-- primeros números primos.
--
-- Definir la función
-- sumSumaPrimos :: Int -> Integer
-- tal que (sumSumaPrimos n) es la suma de n más los n primeros números
-- primos. Por ejemplo,
-- sumSumaPrimos 33 == 2021
-- sumSumaPrimos 52 == 5641
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
sumSumaPrimos :: Int -> Integer
sumSumaPrimos n = toInteger n + sum (take n primosInf)
-- ---------------------------------------------------------------------
-- Ejercicio 2.2. Definir la función
-- esSumSumaPrimos :: Integer -> Bool
-- tal que (esSumSumaPrimos n) se verifica si n es de la suma de m más
-- los m primeros primos, para algún entero m. Por ejemplo,
-- esSumSumaPrimos 2021 == True
-- esSumSumaPrimos 120 == False
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
esSumSumaPrimos :: Integer -> Bool
esSumSumaPrimos n = head (dropWhile (<n) [sumSumaPrimos x | x <- [1.. ]]) == n
-- --------------------------------------------------------------------
-- ejercicio 3. Un número semiprimo es un número natural que es producto
-- de dos números primos no necesariamente distintos. Por ejemplo, 26 es
-- semiprimo (porque 26 = 2×13) y 49 también lo es (porque 49 = 7×7).
--
-- Definir las funciones
-- esSemiprimo :: Integer -> Bool
-- semiprimos :: [Integer]
-- tales que
-- + (esSemiprimo n) se verifica si n es semiprimo. Por ejemplo,
-- esSemiprimo 26 == True
-- esSemiprimo 49 == True
-- esSemiprimo 8 == False
-- esSemiprimo 2021 == True
-- + semiprimos es la sucesión de números semiprimos. Por ejemplo,
-- take 10 semiprimos == [4,6,9,10,14,15,21,22,25,26]
-- semiprimos !! 580 == 2021
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
esSemiprimo :: Integer -> Bool
esSemiprimo n = head (dropWhile (<n) semiprimos) == n
semiprimos :: [Integer]
semiprimos = [x | x <- [4..],not (primo x), divisionDePrimos x]
divisionDePrimos :: Integer -> Bool
divisionDePrimos n = or [primo (div n y) | y <- (primosMenores n), div n y * y == n]
-- --------------------------------------------------------------------
-- Ejercicio 4. Un número natural n es un número entero Blum si
-- n = p × q es un semiprimo para el que p y q son distintos primos
-- congruentes con 3 módulo 4. Es decir, p y q tienen que ser de la
-- forma 4 t + 3, para algún número entero t. Los números enteros de
-- esta forma se denominan números primos de Blum. Los primeros enteros
-- de Blum son
-- 21, 33, 57, 69, 77, 93, 129, 133, 141, 161, 177, ...
--
-- Definir las funciones
-- esBlum :: Integer -> Bool
-- sucBlum :: [Integer]
-- tales que
-- + (esBlum n) se verifica si n es un número de Blum. Por ejemplo,
-- esBlum 26 == False
-- esBlum 49 == False
-- esBlum 77 == True
-- esBlum 2021 == True
-- + sucBlum es la sucesión de números de Blum. Por ejemplo,
-- take 10 sucBlum == [21,33,57,69,77,93,129,133,141,161]
-- sucBlum !! 132 == 2021
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
esBlum :: Integer -> Bool
esBlum n = head (dropWhile (<n) sucBlum) == n
sucBlum :: [Integer]
sucBlum = [x | x <- [21..], not (primo x), divisionDePrimosBlum x]
divisionDePrimosBlum :: Integer -> Bool
divisionDePrimosBlum n = or [primo (div n y) | y <- (primosMenores n), (div n y) /= y, mod y 4 == 3, mod (div n y) 4 == 3, div n y * y == n]
-- --------------------------------------------------------------------
-- Ejercicio 5. Un número semiprimo n = p x q es brillante si p y q
-- tienen el mismo número de dígitos.
--
-- Definir las funciones
-- esBrillante :: Integer -> Bool
-- sucBrillantes :: [Integer]
-- tales que
-- + (esBrillante n) se verifica si n es brillante. Por ejemplo,
-- esBrillante 26 == False
-- esBrillante 49 == True
-- esBrillante 77 == False
-- esBrillante 2021 == True
-- + sucBrillantes es la sucesión de números brillantes. Por ejemplo,
-- take 10 sucBrillante == [4,6,9,10,14,15,21,25,35,49]
-- sucBrillante !! 130 == 2021
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
esBrillante :: Integer -> Bool
esBrillante n = head (dropWhile (<n) sucBrillante) == n
sucBrillante :: [Integer]
sucBrillante = [x | x <- [4..], not (primo x), divisionDePrimosBrillante x]
divisionDePrimosBrillante :: Integer -> Bool
divisionDePrimosBrillante n = or [primo (div n y) | y <- (primosMenores n), numeroDigitos (div n y) == numeroDigitos y, div n y * y == n]
numeroDigitos :: Integer -> Integer
numeroDigitos n | n<10 = 1
| otherwise = numeroDigitos (div n 10) + 1
-- --------------------------------------------------------------------
-- Ejercicio 6.1. Un número natural es amable si se puede expresar como
-- suma de, al menos, dos números naturales consecutivos. Por ejemplo,
-- 2021 es amable pues
-- 2021 = 20 + 21 + ... + 65 + 66.
-- La mayoría de los números naturales son amables, por lo que vamos a
-- calcular la lista de los números no amables.
--
-- Los primeros números no amables son
-- 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
-- 16384, 32768, 65536, 131072, 262144
--
-- Definir la función
-- sucesionesConSuma :: Int -> [(Int,Int)]
-- tal que (sucesionesConSuma n) es la lista de los pares formados por
-- el primero y por el último elemento de las sucesiones de números
-- naturales consecutivos con suma n. Por ejemplo,
-- sucesionesConSuma 15 == [(1,5),(4,6),(7,8)]
-- sucesionesConSuma 2021 == [(20,66),(26,68),(1010,1011)]
-- length (sucesionesConSuma 2021) == 3
-- length (sucesionesConSuma 3000) == 7
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
sucesionesConSuma :: Integer -> [(Integer,Integer)]
sucesionesConSuma n = [(x,y) | x <- [1..n], y <- sucesion x n]
sucesion :: Integer -> Integer -> [Integer]
sucesion x n = [y | y<-[x..(n-1)], (div (y*(y+1)) 2) - (div (x*(x-1)) 2) == n]
-- --------------------------------------------------------------------
-- Ejercicio 6.2. Definir las funciones
-- noAmable :: Integer -> Bool
-- sucNoAmables :: [Integer]
-- tales que
-- + (noAmable n) se verifica si n es un número no amable. Por ejemplo,
-- noAmable 2021 == False
-- noAmable 1024 == True
-- + sucNoAmables es la lista de números naturales no amables. Por
-- ejemplo,
-- take 10 sucNoAmables == [1,2,4,8,16,32,64,128,256,512]
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
noAmable :: Integer -> Bool
noAmable 1 = True
noAmable n = if (div n 2) * 2 == n then noAmable (div n 2) else False
sucNoAmables :: [Integer]
sucNoAmables = [2^x| x<-[0..]]
-- --------------------------------------------------------------------
-- Ejercicio 6.3. Comprobar con QuickCheck que un número natural es no
-- amable si y sólo si es potencia de 2.
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
propNoAmable :: Integer -> Bool
propNoAmable n = noAmable m == (head (dropWhile (<m) [2^x| x <-[0..]]) == m )
where m = 1 + abs n
-- La comprobación es
-- *Main> quickCheck propNoAmable
-- +++ OK, passed 100 tests.
-- --------------------------------------------------------------------
-- Ejercicio 7.1. Un número natural se denomina aritmético si la media
-- aritmética de sus divisores es un número entero.
--
-- Definir la función
-- esAritmetico :: Integer -> Bool
-- tal que (esAritmetico n) se verifica si n es un número aritmético.
-- Por ejemplo,
-- esAritmetico 2021 == True
-- esAritmetico 24 == False
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
esAritmetico :: Integer -> Bool
esAritmetico n = (div (sum (divisores n)) (toInteger(length (divisores n)))) * (toInteger(length (divisores n))) == sum (divisores n)
divisores :: Integer -> [Integer]
divisores n = [x | x <- [1..n], mod n x == 0]
-- --------------------------------------------------------------------
-- Ejercicio 7.2. Comprobar con QuickCheck que todos los primos excepto
-- el 2 son aritméticos.
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
primosAritmeticos :: Int -> Bool
primosAritmeticos n = all esAritmetico (take n (tail primosInf))
-- La comprobación es
-- *Main> quickCheck primosAritmeticos
-- +++ OK, passed 100 tests.
-- --------------------------------------------------------------------
-- Ejercicio 7.3. Definir la función
-- sucAritmeticosConsecutivos :: Int -> [Integer]
-- tal que (sucAritmeticosConsecutivos n) es una sucesión de n números
-- aritméticos consecutivos. Por ejemplo,
-- λ> sucAritmeticosConsecutivos 5
-- [19,20,21,22,23]
-- λ> sucAritmeticosConsecutivos 20
-- [4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,
-- 4968,4969,4970,4971,4972,4973,4974]
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
sucAritmeticosConsecutivos :: Int -> [Integer]
sucAritmeticosConsecutivos n = head (filter consecutivos (segmentosLongitud n sucAritmeticos))
sucAritmeticos :: [Integer]
sucAritmeticos = filter esAritmetico [1..]
segmentosLongitud :: Int -> [a] -> [[a]]
segmentosLongitud n xs = map (take n) (tails xs)
consecutivos :: [Integer] -> Bool
consecutivos ns = all (==1) (zipWith (-) (tail ns) ns)
-- --------------------------------------------------------------------
-- Ejercicio 8.1. El número 2021 tiene las propiedades siguientes:
-- + sumándole su inverso es un número palíndromo: 2021 + 1202 = 3223
-- + multiplicándolo por su inverso también lo es: 2021 * 1202 = 2429242
--
-- Definir las funciones
-- masInvPalindromo :: Integer -> Bool
-- prodInvPalindromo :: Integer -> Bool
-- tales que
-- + (masInvPalindromo n) se verifica si n más su inverso es
-- palíndromo. Por ejemplo,
-- masInvPalindromo 2021 == True
-- masInvPalindromo 109 == False
-- + (prodInvPalindromo n) se verifica si n por su inverso es
-- palíndromo. Por ejemplo,
-- prodInvPalindromo 2021 == True
-- prodInvPalindromo 1097 == False
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
masInvPalindromo :: Integer -> Bool
masInvPalindromo n = digitos (n + numero(reverse(digitos n))) == reverse (digitos (n + numero(reverse(digitos n))))
prodInvPalindromo :: Integer -> Bool
prodInvPalindromo n = digitos (n * numero(reverse(digitos n))) == reverse (digitos (n * numero(reverse(digitos n))))
digitos :: Integer -> [Integer]
digitos n = [read [x] :: Integer | x <- (show n)]
numero :: [Integer] -> Integer
numero [x] = x
numero xs = head xs * 10^(length xs - 1) + numero (tail xs)
-- --------------------------------------------------------------------
-- Ejercicio 8.2. Comprobar con QuickCheck que todo número
-- prodInvPalindromo es masInvPalindromo.
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
propInvPalindromo :: Integer -> Bool
propInvPalindromo n = not (prodInvPalindromo m) || masInvPalindromo m
where m = 1 + abs n
-- La comprobación es
-- *Main> quickCheck propInvPalindromo
-- +++ OK, passed 100 tests.
-- --------------------------------------------------------------------
-- Ejercicio 9. Comprobar que el número 2021 es el menor número
-- natural que verifica las siguientes propiedades:
-- (+) es la concatenación de dos enteros consecutivos (20 y 21)
-- (+) es el producto de dos primos consecutivos (43 y 47)
--
-- Para ello, definir las funciones
-- esConcatConsecutivos :: Integer -> Bool
-- esProdprimosConsecutivos :: Integer -> Bool
-- especiales :: [Integer]
-- tales que
-- + (esConcatConsecutivos n) se verifica si n es la concatenación de
-- dos enteros consecutivos. Por ejemplo,
-- esConcatConsecutivos 2021 == True
-- + (esProdprimosConsecutivos n) se verifica si n es el producto de dos
-- primos consecutivos
-- esProdprimosConsecutivos 2021 == True
-- + especiales es la lista de números naturales que verifican las dos
-- propiedaes anteriores
-- head especiales == 2021
-- ---------------------------------------------------------------------
-- Álvaro Galisteo:
-- esConcatConsecutivos
-- ====================
esConcatConsecutivos :: Integer -> Bool
esConcatConsecutivos n | head( drop (div (length(digitos n)) 2) (digitos n)) == 0 = False
| length (digitos n) == 1 = False
| otherwise = numero (take (div (length(digitos n)) 2) (digitos n)) +1 == numero ( drop (div (length(digitos n)) 2) (digitos n))
-- esProdprimosConsecutivos
-- =========================
esProdprimosConsecutivos :: Integer -> Bool
esProdprimosConsecutivos n = esProdprimosConsecutivosAux n (divisores2 n)
esProdprimosConsecutivosAux :: Integer -> [Integer] -> Bool
esProdprimosConsecutivosAux n [] = False
esProdprimosConsecutivosAux n (x:xs) = if elem (div n x) xs then [x, (div n x)] == take 2 (dropWhile (/=x) primosInf) else esProdprimosConsecutivosAux n xs
divisores2 :: Integer -> [Integer]
divisores2 n = [x | x <- [2..(n-1)], mod n x == 0, primo x]
-- especiales
-- ==========
especiales :: [Integer]
especiales = [x | x <- [1..], esConcatConsecutivos x, esProdprimosConsecutivos x]
-- Primer número especial:
-- *Main> head especiales
-- 2021