Aproximación al límite de sen(x)/x cuando x tiende a cero
El limite de sen(x)/x, cuando x tiende a cero, se puede calcular como el límite de la sucesión sen(1/n)/(1/n), cuando n tiende a infinito.
Definir las funciones
1 2 |
aproxLimSeno :: Int -> [Double] errorLimSeno :: Double -> Int |
tales que
aproxLimSeno n
es la lista de losn
primeros términos de la sucesiónsen(1/m)/(1/m)
. Por ejemplo,
1 2 |
aproxLimSeno 1 == [0.8414709848078965] aproxLimSeno 2 == [0.8414709848078965,0.958851077208406] |
errorLimSeno x
es el menor número de términos de la sucesiónsen(1/m)/(1/m)
necesarios para obtener su límite con un error menor quex
. Por ejemplo,
1 2 3 4 |
errorLimSeno 0.1 == 2 errorLimSeno 0.01 == 5 errorLimSeno 0.001 == 13 errorLimSeno 0.0001 == 41 |
Soluciones
A continuación se muestran las soluciones en Haskell y las soluciones en Python.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
import Test.QuickCheck -- 1ª definición de aproxLimSeno -- ============================= aproxLimSeno1 :: Int -> [Double] aproxLimSeno1 k = [sin(1/n)/(1/n) | n <- [1..k']] where k' = fromIntegral k -- 2ª definición de aproxLimSeno -- ============================= aproxLimSeno2 :: Int -> [Double] aproxLimSeno2 0 = [] aproxLimSeno2 n = aproxLimSeno2 (n-1) ++ [sin(1/n')/(1/n')] where n' = fromIntegral n -- 3ª definición de aproxLimSeno -- ============================= aproxLimSeno3 :: Int -> [Double] aproxLimSeno3 = reverse . aux . fromIntegral where aux 0 = [] aux n = sin(1/n)/(1/n) : aux (n-1) -- 4ª definición de aproxLimSeno -- ============================= aproxLimSeno4 :: Int -> [Double] aproxLimSeno4 k = aux [] (fromIntegral k) where aux xs 0 = xs aux xs n = aux (sin(1/n)/(1/n) : xs) (n-1) -- 5ª definición de aproxLimSeno -- ============================= aproxLimSeno5 :: Int -> [Double] aproxLimSeno5 k = map (\ n -> sin(1/n)/(1/n)) [1..k'] where k' = fromIntegral k -- Comprobación de equivalencia de aproxLimSeno -- ============================================ -- La propiedad es prop_aproxLimSeno :: Positive Int -> Bool prop_aproxLimSeno (Positive k) = all (== aproxLimSeno1 k) [aproxLimSeno2 k, aproxLimSeno3 k, aproxLimSeno4 k, aproxLimSeno5 k] -- La comprobación es -- λ> quickCheck prop_aproxLimSeno -- +++ OK, passed 100 tests. -- Comparación de eficiencia de aproxLimSeno -- ========================================= -- La comparación es -- λ> last (aproxLimSeno1 (2*10^4)) -- 0.9999999995833334 -- (0.01 secs, 5,415,816 bytes) -- λ> last (aproxLimSeno2 (2*10^4)) -- 0.9999999995833334 -- (4.48 secs, 17,514,768,064 bytes) -- λ> last (aproxLimSeno3 (2*10^4)) -- 0.9999999995833334 -- (0.02 secs, 9,530,120 bytes) -- λ> last (aproxLimSeno4 (2*10^4)) -- 0.9999999995833334 -- (0.02 secs, 9,529,968 bytes) -- λ> last (aproxLimSeno5 (2*10^4)) -- 0.9999999995833334 -- (0.01 secs, 4,889,720 bytes) -- -- λ> last (aproxLimSeno1 (2*10^6)) -- 0.9999999999999583 -- (0.46 secs, 480,569,808 bytes) -- λ> last (aproxLimSeno3 (2*10^6)) -- 0.9999999999999583 -- (1.96 secs, 896,569,992 bytes) -- λ> last (aproxLimSeno4 (2*10^6)) -- 0.9999999999999583 -- (1.93 secs, 896,570,048 bytes) -- λ> last (aproxLimSeno5 (2*10^6)) -- 0.9999999999999583 -- (0.05 secs, 432,569,800 bytes) -- -- λ> last (aproxLimSeno1 (10^7)) -- 0.9999999999999983 -- (2.26 secs, 2,400,569,760 bytes) -- λ> last (aproxLimSeno5 (10^7)) -- 0.9999999999999983 -- (0.24 secs, 2,160,569,752 bytes) -- 1ª definición de errorLimSeno -- ============================= errorLimSeno1 :: Double -> Int errorLimSeno1 x = round (head [m | m <- [1..], abs (1 - sin(1/m)/(1/m)) < x]) -- 2ª definición de errorLimSeno -- ============================= errorLimSeno2 :: Double -> Int errorLimSeno2 x = aux 1 where aux n | abs (1 - sin(1/n)/(1/n)) < x = round n | otherwise = aux (n+1) -- 3ª definición de errorLimSeno -- ============================= errorLimSeno3 :: Double -> Int errorLimSeno3 x = round (head (dropWhile (\ n -> abs (1 - sin(1/n)/(1/n)) >= x) [1..])) -- Comprobación de equivalencia de errorLimSeno -- ============================================ -- La propiedad es prop_errorLimSeno :: Positive Double -> Bool prop_errorLimSeno (Positive x) = all (== errorLimSeno1 x) [errorLimSeno2 x, errorLimSeno3 x] -- La comprobación es -- λ> quickCheck prop_errorLimSeno -- +++ OK, passed 100 tests. -- Comparación de eficiencia de errorLimSeno -- ========================================= -- La comparación es -- λ> errorLimSeno1 (10**(-12)) -- 408230 -- (0.41 secs, 206,300,808 bytes) -- λ> errorLimSeno2 (10**(-12)) -- 408230 -- (0.46 secs, 225,895,672 bytes) -- λ> errorLimSeno3 (10**(-12)) -- 408230 -- (0.37 secs, 186,705,688 bytes) |
El código se encuentra en GitHub.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
from itertools import dropwhile, islice from math import sin 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 aproxLimSeno # ============================= def aproxLimSeno1(k: int) -> list[float]: return [sin(1/n)/(1/n) for n in range(1, k + 1)] # 2ª definición de aproxLimSeno # ============================= def aproxLimSeno2(n: int) -> list[float]: if n == 0: return [] return aproxLimSeno2(n - 1) + [sin(1/n)/(1/n)] # 3ª definición de aproxLimSeno # ============================= def aproxLimSeno3(n: int) -> list[float]: def aux(n: int) -> list[float]: if n == 0: return [] return [sin(1/n)/(1/n)] + aux(n - 1) return list(reversed(aux(n))) # 4ª definición de aproxLimSeno # ============================= def aproxLimSeno4(n: int) -> list[float]: def aux(xs: list[float], n: int) -> list[float]: if n == 0: return xs return aux([sin(1/n)/(1/n)] + xs, n - 1) return aux([], n) # 5ª definición de aproxLimSeno # ============================= def aproxLimSeno5(n: int) -> list[float]: return list(map((lambda k: sin(1/k)/(1/k)), range(1, n+1))) # 6ª definición de aproxLimSeno # ============================= def aproxLimSeno6(n: int) -> list[float]: r = [] for k in range(1, n+1): r.append(sin(1/k)/(1/k)) return r # Comprobación de equivalencia de aproxLimSeno # ============================================ # La propiedad es @given(st.integers(min_value=1, max_value=100)) def test_aproxLimSeno(n: int) -> None: r = aproxLimSeno1(n) assert aproxLimSeno2(n) == r assert aproxLimSeno3(n) == r assert aproxLimSeno4(n) == r assert aproxLimSeno5(n) == r assert aproxLimSeno6(n) == r # La comprobación es # src> poetry run pytest -q limite_del_seno.py # 1 passed in 0.60s # Comparación de eficiencia de aproxLimSeno # ========================================= 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('aproxLimSeno1(3*10**5)') # 0.03 segundos # >>> tiempo('aproxLimSeno2(3*10**5)') # Process Python violación de segmento (core dumped) # >>> tiempo('aproxLimSeno3(3*10**5)') # Process Python violación de segmento (core dumped) # >>> tiempo('aproxLimSeno4(3*10**5)') # Process Python violación de segmento (core dumped) # >>> tiempo('aproxLimSeno5(3*10**5)') # 0.04 segundos # >>> tiempo('aproxLimSeno6(3*10**5)') # 0.07 segundos # # >>> tiempo('aproxLimSeno1(10**7)') # 1.29 segundos # >>> tiempo('aproxLimSeno5(10**7)') # 1.40 segundos # >>> tiempo('aproxLimSeno6(10**7)') # 1.45 segundos # 1ª definición de errorLimSeno # ============================ # 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 errorLimSeno1(x: float) -> int: return list(islice((n for n in naturales() if abs(1 - sin(1/n)/(1/n)) < x), 1))[0] # 2ª definición de errorLimSeno # ============================ def errorLimSeno2(x: float) -> int: def aux(n: int) -> int: if abs(1 - sin(1/n)/(1/n)) < x: return n return aux(n + 1) return aux(1) # 3ª definición de errorLimSeno # ============================ def errorLimSeno3(x: float) -> int: return list(islice(dropwhile(lambda n: abs(1 - sin(1/n)/(1/n)) >= x, naturales()), 1))[0] # Comprobación de equivalencia de errorLimSeno # ============================================ @given(st.integers(min_value=1, max_value=100)) def test_errorLimSeno(n: int) -> None: r = errorLimSeno1(n) assert errorLimSeno2(n) == r assert errorLimSeno3(n) == r # La comprobación es # src> poetry run pytest -q limite_del_seno.py # 2 passed in 0.60s # Comparación de eficiencia de errorLimSeno # ========================================= # La comparación es # >>> tiempo('errorLimSeno1(10**(-12))') # 0.07 segundos # >>> tiempo('errorLimSeno2(10**(-12))') # Process Python violación de segmento (core dumped) # >>> tiempo('errorLimSeno3(10**(-12))') # 0.10 segundos |
El código se encuentra en GitHub.