Cálculo de pi mediante la serie de Nilakantha
Una serie infinita para el cálculo de pi, publicada por Nilakantha en el siglo XV, es
Definir las funciones
1 2 |
aproximacionPi :: Int -> Double tabla :: FilePath -> [Int] -> IO () |
tales que
- (aproximacionPi n) es la n-ésima aproximación de pi obtenido sumando los n primeros términos de la serie de Nilakantha. Por ejemplo,
1 2 3 4 5 6 7 8 9 10 11 12 13 |
aproximacionPi 0 == 3.0 aproximacionPi 1 == 3.1666666666666665 aproximacionPi 2 == 3.1333333333333333 aproximacionPi 3 == 3.145238095238095 aproximacionPi 4 == 3.1396825396825396 aproximacionPi 5 == 3.1427128427128426 aproximacionPi 10 == 3.1414067184965018 aproximacionPi 100 == 3.1415924109719824 aproximacionPi 1000 == 3.141592653340544 aproximacionPi 10000 == 3.141592653589538 aproximacionPi 100000 == 3.1415926535897865 aproximacionPi 1000000 == 3.141592653589787 pi == 3.141592653589793 |
- (tabla f ns) escribe en el fichero f las n-ésimas aproximaciones de pi, donde n toma los valores de la lista ns, junto con sus errores. Por ejemplo, al evaluar la expresión
1 |
tabla "AproximacionesPi.txt" [0,10..100] |
hace que el contenido del fichero «AproximacionesPi.txt» sea
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
+------+----------------+----------------+ | n | Aproximación | Error | +------+----------------+----------------+ | 0 | 3.000000000000 | 0.141592653590 | | 10 | 3.141406718497 | 0.000185935093 | | 20 | 3.141565734659 | 0.000026918931 | | 30 | 3.141584272675 | 0.000008380915 | | 40 | 3.141589028941 | 0.000003624649 | | 50 | 3.141590769850 | 0.000001883740 | | 60 | 3.141591552546 | 0.000001101044 | | 70 | 3.141591955265 | 0.000000698325 | | 80 | 3.141592183260 | 0.000000470330 | | 90 | 3.141592321886 | 0.000000331704 | | 100 | 3.141592410972 | 0.000000242618 | +------+----------------+----------------+ |
al evaluar la expresión
1 |
tabla "AproximacionesPi.txt" [0,500..5000] |
hace que el contenido del fichero «AproximacionesPi.txt» sea
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
+------+----------------+----------------+ | n | Aproximación | Error | +------+----------------+----------------+ | 0 | 3.000000000000 | 0.141592653590 | | 500 | 3.141592651602 | 0.000000001988 | | 1000 | 3.141592653341 | 0.000000000249 | | 1500 | 3.141592653516 | 0.000000000074 | | 2000 | 3.141592653559 | 0.000000000031 | | 2500 | 3.141592653574 | 0.000000000016 | | 3000 | 3.141592653581 | 0.000000000009 | | 3500 | 3.141592653584 | 0.000000000006 | | 4000 | 3.141592653586 | 0.000000000004 | | 4500 | 3.141592653587 | 0.000000000003 | | 5000 | 3.141592653588 | 0.000000000002 | +------+----------------+----------------+ |
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 53 54 55 56 57 58 59 60 61 62 63 64 |
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" |
Definición de «aproximacionPi» por recursión: