对无穷级数的有限前缀求和 [英] Summing a finite prefix of an infinite series
问题描述
π
的数字可以通过以下无限序列和来计算:
The number π
can be calculated with the following infinite series sum:
我想定义一个Haskell函数 roughlyPI
,在给定自然数 k
的情况下,该函数计算从 0
到的序列和> k
值.
I want to define a Haskell function roughlyPI
that, given a natural number k
, calculates the series sum from 0
to the k
value.
示例: roughlyPi 1000
(或其他)=> 3.1415926535897922
Example: roughlyPi 1000
(or whatever) => 3.1415926535897922
我所做的就是这个(在VS Code中):
What I did was this (in VS Code):
roughlyPI :: Double -> Double
roughlyPI 0 = 2
roughlyPI n = e1/e2 + (roughlyPI (n-1))
where
e1 = 2**(n+1)*(factorial n)**2
e2 = factorial (2*n +1)
factorial 0 = 1
factorial n = n * factorial (n-1)
但是它并没有真正起作用....
but it doesn't really work....
*Main> roughlyPI 100
NaN
我不知道怎么了.顺便说一下,我是Haskell的新手.
I don't know what's wrong. I'm new to Haskell, by the way.
我真正想要的是能够输入一个数字,该数字最后将给我 PI
.没那么难...
All I really want is to be able to type in a number that will give me PI
at the end. It can't be that hard...
推荐答案
如评论中所述,我们需要避免较大的划分,而应将较小的划分散布在阶乘中.我们使用 Double
表示PI,但即使 Double
也有其局限性.例如 1/0 == Infinity
和(1/0)/(1/0)== Infinity/Infinity == NaN
.
As mentioned in the comments, we need to avoid large divisions and instead intersperse smaller divisions within the factorials. We use Double
for representing PI but even Double
has its limits. For instance 1 / 0 == Infinity
and (1 / 0) / (1 / 0) == Infinity / Infinity == NaN
.
幸运的是,我们可以使用代数来简化公式,并希望延迟 Double
的崩溃.通过将阶乘除以我们的阶乘,数字不会变得太笨拙.
Luckily, we can use algebra to simplify the formula and hopefully delay the blowup of our Double
s. By dividing within our factorial the numbers don't grow too unwieldy too quickly.
此解决方案将计算大约PI 1000
,但由于 2 ^ 1024 :: Double == Infinity
,因此在1023上使用 NaN
时将失败.请注意, fac
的每次迭代如何进行除法和乘法运算以帮助防止数字爆炸.如果您尝试使用计算机来近似PI,我相信会有更好的算法,但是我试图在概念上尽可能地使其接近您的尝试.
This solution will calculate roughlyPI 1000
, but it fails on 1023 with NaN
because 2 ^ 1024 :: Double == Infinity
. Note how each iteration of fac
has a division as well as a multiplication to help keep the numbers from blowing up. If you are trying to approximate PI with a computer, I believe there are better algorithms, but I tried to keep it as conceptually close to your attempt as possible.
roughlyPI :: Integer -> Double
roughlyPI 0 = 2
roughlyPI k = e + roughlyPI (k - 1)
where
k' = fromIntegral k
e = 2 ** (k' + 1) * fac k / (2 * k' + 1)
where
fac 1 = 1 / (k' + 1)
fac p = (fromIntegral p / (k' + fromIntegral p)) * fac (p - 1)
通过使用 realToFrac
(贷方为@leftaroundabout):
We can do better than having a blowup of Double
after 1000 by doing computations with Rationals
then converting to Double
with realToFrac
(credit to @leftaroundabout):
roughlyPI' :: Integer -> Double
roughlyPI' = realToFrac . go
where
go 0 = 2
go k = e + go (k - 1)
where
e = 2 ^ (k + 1) * fac k / (2 * fromIntegral k + 1)
where
fac 1 = 1 % (k + 1)
fac p = (p % (k + p)) * fac (p - 1)
有关更多参考,请参见有关PI近似值的维基百科页面
For further reference see Wikipedia page on approximations of PI
P.S.对不起笨重的方程式,stackoverflow不支持LaTex
P.S. Sorry for the bulky equations, stackoverflow does not support LaTex
这篇关于对无穷级数的有限前缀求和的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!