Primos consecutivos con media capicúa
Definir la list
primosConsecutivosConMediaCapicua :: [(Int,Int,Int)]
formada por las ternas (x,y,z) tales que x e y son primos consecutivos cuya media, z, es capicúa. Por ejemplo,
λ> take 5 primosConsecutivosConMediaCapicua [(3,5,4),(5,7,6),(7,11,9),(97,101,99),(109,113,111)] λ> primosConsecutivosConMediaCapicua !! 500 (5687863,5687867,5687865)
Nota: Escribir las soluciones en Haskell y en Python.
Soluciones
A continuación se muestran las soluciones en Haskell y las soluciones en Python.
1. Soluciones en Haskell
import Data.List (genericTake) import Data.Numbers.Primes (primes) import Test.Hspec (Spec, describe, hspec, it, shouldBe) -- 1ª solución -- =========== primosConsecutivosConMediaCapicua1 :: [(Integer,Integer,Integer)] primosConsecutivosConMediaCapicua1 = [(x,y,z) | (x,y) <- zip primosImpares (tail primosImpares), let z = (x + y) `div` 2, capicua z] -- (primo x) se verifica si x es primo. Por ejemplo, -- primo 7 == True -- primo 8 == False primo :: Integer -> Bool primo x = [y | y <- [1..x], x `rem` y == 0] == [1,x] -- primosImpares es la lista de los números primos impares. Por ejemplo, -- take 10 primosImpares == [3,5,7,11,13,17,19,23,29] primosImpares :: [Integer] primosImpares = [x | x <- [3,5..], primo x] -- (capicua x) se verifica si x es capicúa. Por ejemplo, -- capicua 232 == True -- capicua 223 == False capicua :: Integer -> Bool capicua x = ys == reverse ys where ys = show x -- 2ª solución -- =========== primosConsecutivosConMediaCapicua2 :: [(Integer,Integer,Integer)] primosConsecutivosConMediaCapicua2 = [(x,y,z) | (x,y) <- zip primosImpares2 (tail primosImpares2), let z = (x + y) `div` 2, capicua z] primosImpares2 :: [Integer] primosImpares2 = tail (criba [2..]) where criba (p:ps) = p : criba [n | n <- ps, mod n p /= 0] -- 3ª solución -- =========== primosConsecutivosConMediaCapicua3 :: [(Integer,Integer,Integer)] primosConsecutivosConMediaCapicua3 = [(x,y,z) | (x,y) <- zip (tail primos3) (drop 2 primos3), let z = (x + y) `div` 2, capicua z] primos3 :: [Integer] primos3 = 2 : 3 : criba3 0 (tail primos3) 3 where criba3 k (p:ps) x = [n | n <- [x+2,x+4..p*p-2], and [n `rem` q /= 0 | q <- take k (tail primos3)]] ++ criba3 (k+1) ps (p*p) -- 4ª solución -- =========== primosConsecutivosConMediaCapicua4 :: [(Integer,Integer,Integer)] primosConsecutivosConMediaCapicua4 = [(x,y,z) | (x,y) <- zip (tail primes) (drop 2 primes), let z = (x + y) `div` 2, capicua z] -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG :: [(Integer,Integer,Integer)] -> Spec specG primosConsecutivosConMediaCapicua = do it "e1" $ take 5 primosConsecutivosConMediaCapicua `shouldBe` [(3,5,4),(5,7,6),(7,11,9),(97,101,99),(109,113,111)] spec :: Spec spec = do describe "def. 1" $ specG primosConsecutivosConMediaCapicua1 describe "def. 2" $ specG primosConsecutivosConMediaCapicua2 describe "def. 3" $ specG primosConsecutivosConMediaCapicua3 describe "def. 4" $ specG primosConsecutivosConMediaCapicua4 -- La verificación es -- λ> verifica -- 4 examples, 0 failures -- Equivalencia de definiciones -- ============================ -- La propiedad es prop_primosConsecutivosConMediaCapicua :: Integer -> Bool prop_primosConsecutivosConMediaCapicua n = all (== genericTake n primosConsecutivosConMediaCapicua1) [genericTake n primosConsecutivosConMediaCapicua2, genericTake n primosConsecutivosConMediaCapicua3, genericTake n primosConsecutivosConMediaCapicua4] -- La comprobación es -- λ> prop_primosConsecutivosConMediaCapicua 25 {-# SCC "" #-} -- True -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> primosConsecutivosConMediaCapicua !! 30 -- (12919,12923,12921) -- (4.60 secs, 1,877,064,288 bytes) -- λ> primosConsecutivosConMediaCapicua2 !! 30 -- (12919,12923,12921) -- (0.69 secs, 407,055,848 bytes) -- λ> primosConsecutivosConMediaCapicua3 !! 30 -- (12919,12923,12921) -- (0.07 secs, 18,597,104 bytes) -- λ> primosConsecutivosConMediaCapicua4 !! 30 -- (12919,12923,12921) -- (0.01 secs, 10,065,784 bytes) -- -- λ> primosConsecutivosConMediaCapicua2 !! 40 -- (29287,29297,29292) -- (2.67 secs, 1,775,554,576 bytes) -- λ> primosConsecutivosConMediaCapicua3 !! 40 -- (29287,29297,29292) -- (0.09 secs, 32,325,808 bytes) -- λ> primosConsecutivosConMediaCapicua4 !! 40 -- (29287,29297,29292) -- (0.01 secs, 22,160,072 bytes) -- -- λ> primosConsecutivosConMediaCapicua3 !! 150 -- (605503,605509,605506) -- (3.68 secs, 2,298,403,864 bytes) -- λ> primosConsecutivosConMediaCapicua4 !! 150 -- (605503,605509,605506) -- (0.24 secs, 491,917,240 bytes)
2. Soluciones en Python
from itertools import count, islice from timeit import Timer, default_timer from typing import Iterator from sympy import isprime # 1ª solución # =========== # primo(x) se verifica si x es primo. Por ejemplo, # primo(7) == True # primo(8) == False def primo(x: int) -> bool: return [y for y in range(1, x + 1) if x % y == 0] == [1, x] # primosImpares() genera la lista de los números primos impares. Por # ejemplo, # >>> list(islice(primosImpares(), 10)) # [3, 5, 7, 11, 13, 17, 19, 23, 29, 31] def primosImpares() -> Iterator[int]: return (x for x in count(3, 2) if primo(x)) # capicua(x) se verifica si x es capicúa. Por ejemplo, # capicua(232) == True # capicua(223) == False def capicua(x: int) -> bool: ys = str(x) return ys == ys[::-1] def primosConsecutivosConMediaCapicua1() -> Iterator[tuple[int, int, int]]: return ( (x, y, z) for x, y in zip(primosImpares(), islice(primosImpares(), 1, None)) if (z := (x + y) // 2) and capicua(z) ) # 2ª solución # =========== # Generador de números primos usando la criba de Eratóstenes. def primos2() -> Iterator[int]: no_primos = {} for n in count(2): if n not in no_primos: yield n no_primos[n * n] = [n] else: for p in no_primos[n]: no_primos.setdefault(p + n, []).append(p) del no_primos[n] def primosImpares2() -> Iterator[int]: return islice(primos2(), 1, None) def primosConsecutivosConMediaCapicua2() -> Iterator[tuple[int, int, int]]: return ( (x, y, z) for x, y in zip(primosImpares2(), islice(primosImpares2(), 1, None)) if (z := (x + y) // 2) and capicua(z) ) # 3ª solución # =========== def primosImpares3() -> Iterator[int]: return (n for n in count(3, 2) if isprime(n)) def primosConsecutivosConMediaCapicua3() -> Iterator[tuple[int, int, int]]: return ( (x, y, z) for x, y in zip(primosImpares3(), islice(primosImpares3(), 1, None)) if (z := (x + y) // 2) and capicua(z) ) # Verificación # ============ def test_primosConsecutivosConMediaCapicua() -> None: for primosConsecutivosConMediaCapicua \ in[primosConsecutivosConMediaCapicua1, primosConsecutivosConMediaCapicua2, primosConsecutivosConMediaCapicua3]: assert list(islice(primosConsecutivosConMediaCapicua(), 5)) == \ [(3, 5, 4), (5, 7, 6), (7, 11, 9), (97, 101, 99), (109, 113, 111)] print(f"Verificado {primosConsecutivosConMediaCapicua.__name__}") # La verificación es # >>> test_primosConsecutivosConMediaCapicua() # Verificado primosConsecutivosConMediaCapicua1 # Verificado primosConsecutivosConMediaCapicua2 # Verificado primosConsecutivosConMediaCapicua3 # Equivalencia de definiciones # ============================ # nth(i, n) es el n-ésimo elemento del iterador i. Por ejemplo, # nth(primos2(), 4) == 11 def nth(i: Iterator[int], n: int) -> int: return list(islice(i, n, n+1))[0] # La propiedad es def test_primosConsecutivosConMediaCapicua_equiv() -> None: assert list(islice(primosConsecutivosConMediaCapicua1(), 30)) == \ list(islice(primosConsecutivosConMediaCapicua2(), 30)) assert list(islice(primosConsecutivosConMediaCapicua2(), 100)) == \ list(islice(primosConsecutivosConMediaCapicua3(), 100)) print("Verificado") # La comprobación es # >>> test_primosConsecutivosConMediaCapicua_equiv() # Verificado # Comparación de eficiencia # ========================= def tiempo(e: str) -> None: """Tiempo (en segundos) de evaluar la expresión e.""" t = Timer(e, "", default_timer, globals()).timeit(1) print(f"{t:0.2f} segundos") # La comparación es # >>> tiempo('nth(primosConsecutivosConMediaCapicua1(), 30)') # 4.17 segundos # >>> tiempo('nth(primosConsecutivosConMediaCapicua2(), 30)') # 0.02 segundos # >>> tiempo('nth(primosConsecutivosConMediaCapicua3(), 30)') # 0.04 segundos # # >>> tiempo('nth(primosConsecutivosConMediaCapicua2(), 200)') # 1.54 segundos # >>> tiempo('nth(primosConsecutivosConMediaCapicua3(), 200)') # 3.33 segundos