Aproximación del número e
El número e se define como el límite de la sucesión [latex]\left(1+\dfrac{1}{n}\right)^n[/latex].
Definir las funciones
aproxE :: Int -> [Double] errorAproxE :: Double -> Int
tales que
-
aproxE k
es la lista de losk
primeros términos de la sucesión. Por ejemplo,
aproxE 4 == [2.0,2.25,2.37037037037037,2.44140625] last (aproxE (7*10^7)) == 2.7182818287372563
-
errorE x
es el menor número de términos de la sucesión necesarios para obtener su límite con un error menor quex
. Por ejemplo,
errorAproxE 0.1 == 13 errorAproxE 0.01 == 135 errorAproxE 0.001 == 1359
Soluciones en Haskell
import Test.QuickCheck -- 1ª definición de aproxE -- ======================= aproxE1 :: Int -> [Double] aproxE1 k = [(1+1/n)**n | n <- [1..k']] where k' = fromIntegral k -- 2ª definición de aproxE -- ======================= aproxE2 :: Int -> [Double] aproxE2 0 = [] aproxE2 n = aproxE2 (n-1) ++ [(1+1/n')**n'] where n' = fromIntegral n -- 3ª definición de aproxE -- ======================= aproxE3 :: Int -> [Double] aproxE3 = reverse . aux . fromIntegral where aux 0 = [] aux n = (1+1/n)**n : aux (n-1) -- 4ª definición de aproxE -- ======================= aproxE4 :: Int -> [Double] aproxE4 k = aux [] (fromIntegral k) where aux xs 0 = xs aux xs n = aux ((1+1/n)**n : xs) (n-1) -- 5ª definición de aproxE -- ======================= aproxE5 :: Int -> [Double] aproxE5 k = map (\ n -> (1+1/n)**n) [1..k'] where k' = fromIntegral k -- Comprobación de equivalencia de aproxE -- ====================================== -- La propiedad es prop_aproxE :: Positive Int -> Bool prop_aproxE (Positive k) = all (== aproxE1 k) [aproxE2 k, aproxE3 k, aproxE4 k, aproxE5 k] -- La comprobación es -- λ> quickCheck prop_aproxE -- +++ OK, passed 100 tests. -- Comparación de eficiencia de aproxE -- =================================== -- La comparación es -- λ> last (aproxE1 (2*10^4)) -- 2.718213874533619 -- (0.04 secs, 5,368,968 bytes) -- λ> last (aproxE2 (2*10^4)) -- 2.718213874533619 -- (5.93 secs, 17,514,767,104 bytes) -- λ> last (aproxE3 (2*10^4)) -- 2.718213874533619 -- (0.05 secs, 9,529,336 bytes) -- λ> last (aproxE4 (2*10^4)) -- 2.718213874533619 -- (0.05 secs, 9,529,184 bytes) -- λ> last (aproxE5 (2*10^4)) -- 2.718213874533619 -- (0.01 secs, 4,888,960 bytes) -- -- λ> last (aproxE1 (2*10^6)) -- 2.7182811492688552 -- (0.54 secs, 480,570,120 bytes) -- λ> last (aproxE3 (2*10^6)) -- 2.7182811492688552 -- (2.07 secs, 896,570,280 bytes) -- λ> last (aproxE4 (2*10^6)) -- 2.7182811492688552 -- (2.18 secs, 896,570,336 bytes) -- λ> last (aproxE5 (2*10^6)) -- 2.7182811492688552 -- (0.09 secs, 432,570,112 bytes) -- 1ª definición de errorAproxE -- ============================ errorAproxE1 :: Double -> Int errorAproxE1 x = round (head [n | n <- [1..], abs (exp 1 - (1+1/n)**n) < x]) -- 2ª definición de errorAproxE -- ============================ errorAproxE2 :: Double -> Int errorAproxE2 x = aux 1 where aux n | abs (exp 1 - (1+1/n)**n) < x = round n | otherwise = aux (n+1) -- 3ª definición de errorAproxE -- ============================ errorAproxE3 :: Double -> Int errorAproxE3 x = round (head (dropWhile (\ n -> abs (exp 1 - (1+1/n)**n) >= x) [1..])) -- Comprobación de equivalencia de errorAproxE -- =========================================== -- La propiedad es prop_errorAproxE :: Positive Double -> Bool prop_errorAproxE (Positive x) = all (== errorAproxE1 x) [errorAproxE2 x, errorAproxE3 x] -- La comprobación es -- λ> quickCheck prop_errorAproxE -- +++ OK, passed 100 tests. -- Comparación de eficiencia de errorAproxE -- ======================================== -- La comparación es -- λ> errorAproxE1 0.000001 -- 1358611 -- (1.70 secs, 674,424,552 bytes) -- λ> errorAproxE2 0.000001 -- 1358611 -- (1.79 secs, 739,637,704 bytes) -- λ> errorAproxE3 0.000001 -- 1358611 -- (1.20 secs, 609,211,144 bytes)
El código se encuentra en GitHub.
Soluciones en Python
from itertools import dropwhile, islice from math import e from sys import setrecursionlimit from timeit import Timer, default_timer from typing import Iterator from hypothesis import given from hypothesis import strategies as st setrecursionlimit(10**6) # 1ª definición de aproxE # ======================= def aproxE1(k: int) -> list[float]: return [(1 + 1/n)**n for n in range(1, k + 1)] # 2ª definición de aproxE # ======================= def aproxE2(n: int) -> list[float]: if n == 0: return [] return aproxE2(n - 1) + [(1 + 1/n)**n] # 3ª definición de aproxE # ======================= def aproxE3(n: int) -> list[float]: def aux(n: int) -> list[float]: if n == 0: return [] return [(1 + 1/n)**n] + aux(n - 1) return list(reversed(aux(n))) # 4ª definición de aproxE # ======================= def aproxE4(n: int) -> list[float]: def aux(xs: list[float], n: int) -> list[float]: if n == 0: return xs return aux([(1 + 1/n)**n] + xs, n - 1) return aux([], n) # 5ª definición de aproxE # ======================= def aproxE5(n: int) -> list[float]: return list(map((lambda k: (1+1/k)**k), range(1, n+1))) # 6ª definición de aproxE # ======================= def aproxE6(n: int) -> list[float]: r = [] for k in range(1, n+1): r.append((1+1/k)**k) return r # Comprobación de equivalencia de aproxE # ====================================== # La propiedad es @given(st.integers(min_value=1, max_value=100)) def test_aproxE(n: int) -> None: r = aproxE1(n) assert aproxE2(n) == r assert aproxE3(n) == r assert aproxE4(n) == r assert aproxE5(n) == r assert aproxE6(n) == r # La comprobación es # src> poetry run pytest -q aproximacion_del_numero_e.py # 1 passed in 0.60s # Comparación de eficiencia de aproxE # =================================== def tiempo(ex: str) -> None: """Tiempo (en segundos) de evaluar la expresión e.""" t = Timer(ex, "", default_timer, globals()).timeit(1) print(f"{t:0.2f} segundos") # La comparación es # >>> tiempo('aproxE1(20000)') # 0.00 segundos # >>> tiempo('aproxE2(20000)') # 0.43 segundos # >>> tiempo('aproxE3(20000)') # 0.60 segundos # >>> tiempo('aproxE4(20000)') # 1.23 segundos # >>> tiempo('aproxE5(20000)') # 0.00 segundos # >>> tiempo('aproxE6(20000)') # 0.00 segundos # >>> tiempo('aproxE1(10**7)') # 1.18 segundos # >>> tiempo('aproxE5(10**7)') # 1.48 segundos # >>> tiempo('aproxE6(10**7)') # 1.43 segundos # 1ª definición de errorAproxE # ============================ # naturales es el generador de los números naturales positivos, Por # ejemplo, # >>> list(islice(naturales(), 5)) # [1, 2, 3, 4, 5] def naturales() -> Iterator[int]: i = 1 while True: yield i i += 1 def errorAproxE1(x: float) -> int: return list(islice((n for n in naturales() if abs(e - (1 + 1/n)**n) < x), 1))[0] # # 2ª definición de errorAproxE # # ============================ def errorAproxE2(x: float) -> int: def aux(n: int) -> int: if abs(e - (1 + 1/n)**n) < x: return n return aux(n + 1) return aux(1) # 3ª definición de errorAproxE # ============================ def errorAproxE3(x: float) -> int: return list(islice(dropwhile(lambda n: abs(e - (1 + 1/n)**n) >= x, naturales()), 1))[0] # Comprobación de equivalencia de errorAproxE # =========================================== @given(st.integers(min_value=1, max_value=100)) def test_errorAproxE(n: int) -> None: r = errorAproxE1(n) assert errorAproxE2(n) == r assert errorAproxE3(n) == r # La comprobación es # src> poetry run pytest -q aproximacion_del_numero_e.py # 2 passed in 0.60s # Comparación de eficiencia de aproxE # =================================== # La comparación es # >>> tiempo('errorAproxE1(0.0001)') # 0.00 segundos # >>> tiempo('errorAproxE2(0.0001)') # 0.00 segundos # >>> tiempo('errorAproxE3(0.0001)') # 0.00 segundos # # >>> tiempo('errorAproxE1(0.0000001)') # 2.48 segundos # >>> tiempo('errorAproxE3(0.0000001)') # 2.61 segundos
El código se encuentra en GitHub.