Sumas alternas de factoriales
Las primeras sumas alternas de los factoriales son números primos; en efecto,
3! - 2! + 1! = 5 4! - 3! + 2! - 1! = 19 5! - 4! + 3! - 2! + 1! = 101 6! - 5! + 4! - 3! + 2! - 1! = 619 7! - 6! + 5! - 4! + 3! - 2! + 1! = 4421 8! - 7! + 6! - 5! + 4! - 3! + 2! - 1! = 35899
son primos, pero
9! - 8! + 7! - 6! + 5! - 4! + 3! - 2! + 1! = 326981
no es primo.
Definir las funciones
sumaAlterna :: Integer -> Integer sumasAlternas :: [Integer] conSumaAlternaPrima :: [Integer]
tales que
- (sumaAlterna n) es la suma alterna de los factoriales desde n hasta 1. Por ejemplo,
sumaAlterna 3 == 5 sumaAlterna 4 == 19 sumaAlterna 5 == 101 sumaAlterna 6 == 619 sumaAlterna 7 == 4421 sumaAlterna 8 == 35899 sumaAlterna 9 == 326981
- sumasAlternas es la sucesión de las sumas alternas de factoriales. Por ejemplo,
λ> take 10 sumasAlternas [0,1,1,5,19,101,619,4421,35899,326981]
- conSumaAlternaPrima es la sucesión de los números cuya suma alterna de factoriales es prima. Por ejemplo,
λ> take 8 conSumaAlternaPrima [3,4,5,6,7,8,10,15]
Soluciones
import Data.List (cycle, genericTake) import Data.Numbers.Primes (isPrime) Definiciones de sumaAlterna -- =========================== -- 1ª definición -- ------------- sumaAlterna1 :: Integer -> Integer sumaAlterna1 1 = 1 sumaAlterna1 n = factorial n - sumaAlterna1 (n-1) factorial :: Integer -> Integer factorial n = product [1..n] -- 2ª definición -- ------------- sumaAlterna2 :: Integer -> Integer sumaAlterna2 n = sum (zipWith (*) signos (tail factoriales)) where signos | odd n = 1 : concat (replicate (m `div` 2) [-1,1]) | otherwise = concat (replicate (m `div` 2) [-1,1]) m = fromIntegral n -- factoriales es la lista de los factoriales. Por ejemplo, -- take 7 factoriales == [1,1,2,6,24,120,720] factoriales :: [Integer] factoriales = 1 : scanl1 (*) [1..] -- 3ª definición -- ------------- sumaAlterna3 :: Integer -> Integer sumaAlterna3 n = sum (genericTake n (zipWith (*) signos (tail factoriales))) where signos | odd n = cycle [1,-1] | otherwise = cycle [-1,1] -- Comparación de eficiencia -- ------------------------- -- λ> sumaAlterna1 3000 `mod` (10^6) -- 577019 -- (5.33 secs, 7,025,937,760 bytes) -- λ> sumaAlterna2 3000 `mod` (10^6) -- 577019 -- (0.03 secs, 15,738,480 bytes) -- λ> sumaAlterna3 3000 `mod` (10^6) -- 577019 -- (0.05 secs, 16,520,896 bytes) -- En lo que sigue se usa la 2ª definición sumaAlterna :: Integer -> Integer sumaAlterna = sumaAlterna2 sumasAlternas -- ============= -- 1ª definición -- ------------- sumasAlternas1 :: [Integer] sumasAlternas1 = [sumaAlterna n | n <- [0..]] -- 2ª definición -- ------------- sumasAlternas2 :: [Integer] sumasAlternas2 = 0 : zipWith (-) (tail factoriales) sumasAlternas2 Definiciones de conSumaAlternaPrima =================================== -- 1ª definición -- ------------- conSumaAlternaPrima1 :: [Integer] conSumaAlternaPrima1 = [n | n <- [0..], isPrime (sumaAlterna n)] -- 2ª definición -- ------------- conSumaAlternaPrima2 :: [Integer] conSumaAlternaPrima2 = [x | (x,y) <- zip [0..] sumasAlternas2, isPrime y]