Ir al contenido principal

Parte impar de un número


Todo número entero \(n\) se puede escribir como \(m \times 2^k\), con \(m\) impar. Se dice que \(m\) es la parte impar de \(n\). Por ejemplo, la parte impar de 40 es 5 porque 40 = \(5 \times 2^3\).

Definir la función

parteImpar :: Int -> Int

tal que (parteImpar n) es la parte impar de n. Por ejemplo,

parteImpar 40  ==  5

Soluciones

import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

-- 1ª solución
-- ===========

parteImpar1 :: Integer -> Integer
parteImpar1 n | even n    = parteImpar1 (n `div` 2)
              | otherwise = n

-- 2ª solución
-- ===========

parteImpar2 :: Integer -> Integer
parteImpar2 = until odd (`div` 2)

-- 3ª solución
-- ===========

parteImpar3 :: Integer -> Integer
parteImpar3 n =
  n `div` (2 ^ length (takeWhile even (iterate (`div` 2) n)))

-- Verificación
-- ============

verifica :: IO ()
verifica = hspec spec

specG :: (Integer -> Integer) -> Spec
specG parteImpar = do
  it "e1" $
    parteImpar 40 `shouldBe`  5

spec :: Spec
spec = do
  describe "def. 1" $ specG parteImpar1
  describe "def. 2" $ specG parteImpar2
  describe "def. 3" $ specG parteImpar3

-- La verificación es
--    λ> verifica
--    2 examples, 0 failures

-- Comprobación de equivalencia
-- ============================

-- La propiedad de equivalencia es
prop_parteImpar :: Positive Integer -> Bool
prop_parteImpar (Positive n) =
  all (== parteImpar1 n)
      [parteImpar2 n,
       parteImpar3 n]

-- La comprobación es
--    λ> quickCheck prop_parteImpar
--    +++ OK, passed 100 tests.

-- Comparación de eficiencia
-- =========================

-- La comparación es
--    λ> parteImpar1 (2^300000)
--    1
--    (2.88 secs, 5,708,547,096 bytes)
--    λ> parteImpar2 (2^300000)
--    1
--    (2.82 secs, 5,677,346,992 bytes)
--    λ> parteImpar3 (2^300000)
--    1
--    (2.81 secs, 5,711,063,584 bytes)