Suma de divisores
Definir las funciones
divisores :: Integer -> [Integer] sumaDivisores :: Integer -> Integer
tales que
- (divisores x) es la lista de los divisores de x. Por ejemplo,
divisores 12 == [1,2,3,4,6,12] divisores 25 == [1,5,25] length (divisores (product [1..12])) == 792 length (divisores 131535436245601) == 32
- (sumaDivisores x) es la suma de los divisores de x. Por ejemplo,
sumaDivisores 12 == 28 sumaDivisores 25 == 31 sumaDivisores (product [1..12]) == 2217441408 sumaDivisores 131535436245601 == 132534784471040
Soluciones
import Data.List (group, inits, nub, sort, subsequences) import Data.Numbers.Primes (primeFactors) -- 1ª definición de divisores divisores1 :: Integer -> [Integer] divisores1 x = [y | y <- [1..x] , x `mod` y == 0] -- 2ª definición de divisores divisores2 :: Integer -> [Integer] divisores2 n = filter ((== 0) . mod n) [1..n] -- 3ª definición de divisores divisores3 :: Integer -> [Integer] divisores3 = nub . sort . map product . subsequences . primeFactors -- 4ª definición -- ============= divisores4 :: Integer -> [Integer] divisores4 = sort . map (product . concat) . productoCartesiano . map inits . group . primeFactors -- (producto xss) es el producto cartesiano de los conjuntos xss. Por -- ejemplo, -- λ> producto [[1,3],[2,5],[6,4]] -- [[1,2,6],[1,2,4],[1,5,6],[1,5,4],[3,2,6],[3,2,4],[3,5,6],[3,5,4]] productoCartesiano :: [[a]] -> [[a]] productoCartesiano [] = [[]] productoCartesiano (xs:xss) = [x:ys | x <- xs, ys <- productoCartesiano xss] -- Comparación de eficiencia de divisores -- λ> length (divisores1 (product [1..10])) -- 270 -- (5.32 secs, 725,922,264 bytes) -- λ> length (divisores2 (product [1..10])) -- 270 -- (1.75 secs, 435,611,632 bytes) -- λ> length (divisores3 (product [1..10])) -- 270 -- (0.09 secs, 51,079,512 bytes) -- λ> length (divisores4 (product [1..10])) -- 270 -- (0.02 secs, 863,768 bytes) -- -- λ> length (divisores3 13082761331670030) -- 16384 -- (49.89 secs, 25,296,488 bytes) -- λ> length (divisores4 13082761331670030) -- 16384 -- (0.25 secs, 78,694,200 bytes) -- En lo que sigue usamos la 4ª definición de divisores divisores :: Integer -> [Integer] divisores = divisores4 -- 1ª definición de sumaDivisores sumaDivisores :: Integer -> Integer sumaDivisores = sum . divisores -- 2ª definición de sumaDivisores -- ============================== -- Si la descomposición de x en factores primos es -- x = p(1)^e(1) . p(2)^e(2) . .... . p(n)^e(n) -- entonces la suma de los divisores de x es -- p(1)^(e(1)+1) - 1 p(2)^(e(2)+1) - 1 p(n)^(e(2)+1) - 1 -- ------------------- . ------------------- ... ------------------- -- p(1)-1 p(2)-1 p(n)-1 -- Ver la demostración en http://bit.ly/2zUXZPc sumaDivisores2 :: Integer -> Integer sumaDivisores2 x = product [(p^(e+1)-1) `div` (p-1) | (p,e) <- basesYexponentes x] -- (basesYexponentes x) son las bases y exponentes de la descomposición -- prima de x. Por ejemplo, -- basesYexponentes 18000 == [(2,4),(3,2),(5,3)] basesYexponentes :: Integer -> [(Integer,Integer)] basesYexponentes x = map primeroYlongitud (group (primeFactors x)) -- (primeroYlongitus) xs es el par formado por el primer elemento de xs -- y la longitud de xs. Por ejemplo, -- primeroYlongitud [3,2,5,7] == (3,4) primeroYlongitud :: [a] -> (a,Integer) primeroYlongitud (x:xs) = (x, 1 + genericLength xs) -- Comparación de eficiencia de sumaDivisores -- ========================================== -- λ> sumaDivisores 251888923423315469521109880000000 -- 1471072204661054993275791673480320 -- (10.43 secs, 10,658,208,360 bytes) -- λ> sumaDivisores2 251888923423315469521109880000000 -- 1471072204661054993275791673480320 -- (0.00 secs, 223,488 bytes)