Cálculo de pi mediante la variante de Euler de la serie armónica
En el artículo El desarrollo más bello de Pi como suma infinita, Miguel Ángel Morales comenta el desarrollo de pi publicado por Leonhard Euler en su libro «Introductio in Analysis Infinitorum» (1748).
El desarrollo es el siguiente
y se obtiene a partir de la serie armónica
modificando sólo el signo de algunos términos según el siguiente criterio:
- Dejamos un + cuando el denominador de la fracción sea un 2 o un primo de la forma 4m-1.
- Cambiamos a – si el denominador de la fracción es un primo de la forma 4m+1.
- Si el número es compuesto ponemos el signo que quede al multiplicar los signos correspondientes a cada factor.
Por ejemplo,
- la de denominador 3 = 4×1-1 lleva un +,
- la de denominador 5 = 4×1+1 lleva un -,
- la de denominador 13 = 4×3+1 lleva un -,
- la de denominador 6 = 2×3 lleva un + (porque los dos llevan un +),
- la de denominador 10 = 2×5 lleva un – (porque el 2 lleva un + y el 5 lleva un -) y
- la de denominador 50 = 5x5x2 lleva un + (un – por el primer 5, otro – por el segundo 5 y un + por el 2).
Definir las funciones
1 2 |
aproximacionPi :: Int -> Double grafica :: Int -> IO () |
tales que
- (aproximacionPi n) es la aproximación de pi obtenida sumando los n primeros términos de la serie de Euler. Por ejemplo.
1 2 3 4 5 6 7 |
aproximacionPi 1 == 1.0 aproximacionPi 10 == 2.3289682539682537 aproximacionPi 100 == 2.934318000847734 aproximacionPi 1000 == 3.0603246224585128 aproximacionPi 10000 == 3.1105295744825403 aproximacionPi 100000 == 3.134308801935256 aproximacionPi 1000000 == 3.1395057903490806 |
- (grafica n) dibuja la gráfica de las aproximaciones de pi usando k sumando donde k toma los valores de la lista [100,110..n]. Por ejemplo, al evaluar (grafica 4000) se obtiene
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 |
import Data.Numbers.Primes import Graphics.Gnuplot.Simple -- 1ª definición -- ============= aproximacionPi :: Int -> Double aproximacionPi n = sum [1 / fromIntegral (k * signo k) | k <- [1..n]] signoPrimo :: Int -> Int signoPrimo 2 = 1 signoPrimo p | p `mod` 4 == 3 = 1 | otherwise = -1 signo :: Int -> Int signo n | isPrime n = signoPrimo n | otherwise = product (map signoPrimo (primeFactors n)) -- 2ª definición -- ============= aproximacionPi2 :: Int -> Double aproximacionPi2 n = serieEuler !! (n-1) serieEuler :: [Double] serieEuler = scanl1 (+) [1 / fromIntegral (n * signo n) | n <- [1..]] -- Definición de grafica -- ===================== grafica :: Int -> IO () grafica n = plotList [Key Nothing] [(k,aproximacionPi2 k) | k <- [100,110..n]] |
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>
3 Comentarios