Cálculo de pi con el producto de Wallis
El producto de Wallis es una expresión, descubierta por John Wallis en 1655, para representar el valor de π y que establece que:
1 2 3 |
π 2 2 4 4 6 6 8 8 --- = --- · --- · --- · --- · --- · --- · --- · --- ··· 2 1 3 3 5 5 7 7 9 |
Definir las funciones
1 2 3 4 |
factoresWallis :: [Rational] productosWallis :: [Rational] aproximacionPi :: Int -> Double errorPi :: Double -> Int |
tales que
- factoresWallis es la sucesión de los factores del productos de Wallis. Por ejemplo,
1 2 |
λ> take 10 factoresWallis [2 % 1,2 % 3,4 % 3,4 % 5,6 % 5,6 % 7,8 % 7,8 % 9,10 % 9,10 % 11] |
- productosWallis es la sucesión de los productos de los primeros factores de Wallis. Por ejemplo,
1 2 |
λ> take 7 productosWallis [2 % 1,4 % 3,16 % 9,64 % 45,128 % 75,256 % 175,2048 % 1225] |
- (aproximacionPi n) es la aproximación de pi obtenida multiplicando los n primeros factores de Wallis. Por ejemplo,
1 2 3 4 |
aproximacionPi 20 == 3.2137849402931895 aproximacionPi 200 == 3.1493784731686008 aproximacionPi 2000 == 3.142377365093878 aproximacionPi 20000 == 3.141671186534396 |
- (errorPi x) es el menor número de factores de Wallis necesarios para obtener pi con un error menor que x. Por ejemplo,
1 2 3 4 |
errorPi 0.1 == 14 errorPi 0.01 == 155 errorPi 0.001 == 1569 errorPi 0.0001 == 15707 |
Soluciones
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 |
import Data.Ratio factoresWallis :: [Rational] factoresWallis = concat [[y%(y-1), y%(y+1)] | x <- [1..], let y = 2*x] productosWallis :: [Rational] productosWallis = scanl1 (*) factoresWallis aproximacionPi :: Int -> Double aproximacionPi n = fromRational (2 * productosWallis !! n) errorPi :: Double -> Int errorPi x = head [n | n <- [1..] , abs (pi - aproximacionPi n) < x] -- 2ª definición de errorPi errorPi2 :: Double -> Int errorPi2 x = length (takeWhile (>=x) [abs (pi - 2 * fromRational y) | y <- productosWallis]) -- 2ª definición de aproximacionPi aproximacionPi2 :: Int -> Double aproximacionPi2 n = 2 * productosWallis2 !! n productosWallis2 :: [Double] productosWallis2 = scanl1 (*) factoresWallis2 factoresWallis2 :: [Double] factoresWallis2 = concat [[y/(y-1), y/(y+1)] | x <- [1..], let y = 2*x] -- 3ª definición de errorPi errorPi3 :: Double -> Int errorPi3 x = head [n | n <- [1..] , abs (pi - aproximacionPi2 n) < x] -- Comparación de eficiencia -- λ> errorPi 0.001 -- 1569 -- (0.82 secs, 374,495,816 bytes) -- -- λ> errorPi2 0.001 -- 1569 -- (0.79 secs, 369,282,320 bytes) -- -- λ> errorPi3 0.001 -- 1569 -- (0.04 secs, 0 bytes) |
Otras soluciones
- Se pueden escribir otras soluciones en los comentarios.
- El código se debe escribir entre una línea con <pre lang="haskell"> y otra con </pre>
Pensamiento
«¿Por qué son hermosos los números? Es como preguntar por qué es bella la Novena Sinfonía de Beethoven. Si no ves por qué, alguien no puede decírtelo. Yo sé que los números son hermosos. Si no son hermosos, nada lo es.»