Órbita prima
La órbita prima de un número n
es la sucesión construida de la siguiente forma:
- si
n
es compuesto su órbita no tiene elementos - si
n
es primo, entoncesn
está en su órbita; además, sumamosn
y sus dígitos, si el resultado es un número primo repetimos el proceso hasta obtener un número compuesto.
Por ejemplo, con el 11 podemos repetir el proceso dos veces
13 = 11+1+1 17 = 13+1+3
Así, la órbita prima de 11 es 11, 13, 17.
Definir la función
orbita :: Integer -> [Integer]
tal que (orbita n)
es la órbita prima de n
. Por ejemplo,
orbita 11 == [11,13,17] orbita 59 == [59,73,83]
Calcular el menor número cuya órbita prima tiene más de 3 elementos.
Soluciones
import Data.Numbers.Primes (isPrime) import Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck (quickCheck) -- 1ª solución -- =========== orbita1 :: Integer -> [Integer] orbita1 n | not (esPrimo n) = [] | otherwise = n : orbita1 (n + sum (digitos n)) -- (esPrimo n) se verifica si n es primo. Por ejemplo, -- esPrimo 7 == True -- esPrimo 15 == False esPrimo :: Integer -> Bool esPrimo n = [x | x <- [1..n], n `rem` x == 0] == [1,n] -- (digitos n) es la lista de los dígitos de n. Por ejemplo, -- digitos 15 == [1,5] digitos :: Integer -> [Integer] digitos n = [read [x]| x <- show n] -- 2ª solución -- =========== orbita2 :: Integer -> [Integer] orbita2 n = takeWhile esPrimo (iterate f n) where f x = x + sum (digitos x) -- 3ª solución -- =========== orbita3 :: Integer -> [Integer] orbita3 n = takeWhile isPrime (iterate f n) where f x = x + sum (digitos x) -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG :: (Integer -> [Integer]) -> Spec specG orbita = do it "e1" $ orbita 11 `shouldBe` [11,13,17] it "e2" $ orbita 59 `shouldBe` [59,73,83] spec :: Spec spec = do describe "def. 1" $ specG orbita1 describe "def. 2" $ specG orbita2 describe "def. 3" $ specG orbita3 -- La verificación es -- λ> verifica -- 6 examples, 0 failures -- Comprobación de equivalencia -- ============================ -- La propiedad es prop_orbita :: Integer -> Bool prop_orbita n = all (== orbita1 n) [orbita2 n, orbita3 n] -- La comprobación es -- λ> quickCheck prop_orbita -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> orbita2 516493 -- [516493,516521,516541,516563,516589,516623] -- (1.14 secs, 620,631,072 bytes) -- λ> orbita3 516493 -- [516493,516521,516541,516563,516589,516623] -- (0.01 secs, 2,340,984 bytes) -- Cálculo -- ======= -- El cálculo es -- λ> head [x | x <- [1,3..], length (orbita3 x) > 3] -- 277 -- -- λ> orbita3 277 -- [277,293,307,317]