import Text.Printf
-- 1ª solución
-- ===========
aproximacionPi :: Int -> Double
aproximacionPi n = serieNilakantha !! n
serieNilakantha :: [Double]
serieNilakantha = scanl1 (+) terminosNilakantha
terminosNilakantha :: [Double]
terminosNilakantha = zipWith (/) numeradores denominadores
where numeradores = 3 : cycle [4,-4]
denominadores = 1 : [n*(n+1)*(n+2) | n <- [2,4..]]
-- 2ª solución
-- ===========
aproximacionPi2 :: Int -> Double
aproximacionPi2 = aux 3 2 1
where aux x _ _ 0 = x
aux x y z m =
aux (x+4/product[y..y+2]*z) (y+2) (negate z) (m-1)
-- Comparación de eficiencia
-- =========================
-- λ> aproximacionPi (2*10^5)
-- 3.141592653589787
-- (0.82 secs, 145,964,728 bytes)
-- λ> aproximacionPi2 (2*10^5)
-- 3.141592653589787
-- (2.27 secs, 432,463,496 bytes)
-- λ> aproximacionPi (3*10^5)
-- 3.141592653589787
-- (0.34 secs, 73,056,488 bytes)
-- λ> aproximacionPi2 (3*10^5)
-- 3.141592653589787
-- (3.24 secs, 648,603,824 bytes)
-- Definicioń de tabla
-- ===================
tabla :: FilePath -> [Int] -> IO ()
tabla f ns = do
writeFile f (tablaAux ns)
tablaAux :: [Int] -> String
tablaAux ns =
linea
++ cabecera
++ linea
++ concat [printf "| %4d | %.12f | %.12f |\n" n a e
| n <- ns
, let a = aproximacionPi n
, let e = abs (pi - a)]
++ linea
linea :: String
linea = "+------+----------------+----------------+\n"
cabecera :: String
cabecera = "| n | Aproximación | Error |\n"