! 没写完,先别看T.T
在人类发展的历史长河上,PI是美妙的,同时也是人类认知圆这一图形的钥匙。既然PI是一个无理数,那么自然我们需要用一定的算法才可以进行迭代解算,本文将对几个经典算法进行实现。
1. 计算公式
自从1593年伟大的数学家韦达发现了使用无穷乘积来计算π后,全世界各地的神人们都研究并发表了很多的计算方法,以下是常见的几种:
(图片引用自:http://tieba.baidu.com/p/1392156294)
外加一个Newton-Leibniz: pi = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) …(实测这个方法很好用啊 _(:з」∠)_ )
上述算法实现起来非常简单,但是,π的计算重在一个精确,动辄就是好几百位几千位的小数,在不考虑我们可爱的大数乘除法的前提下,这明显不讲理嘛,我们不禁思考:计算机能够表示这么长的数吗?
于是乎,我开始查阅论文。。。
查阅中,请稍后。。。
。
。
。
。
图书馆网速好慢
。
。
。
额,我们还是先把代码实现出来吧。
2. 系统架构
1) class: Algorithm
就是放置各种算法的一个类
#include <math.h>
#include <iostream>
class Algorithm
{
public:
Algorithm();
long double Vieta(long int iterationNum);
long double Leibniz(long int iterationNum);
long double Newton(long int iterationNum);
long double Newton_Leibniz(long int iterationNum);
long double Sharp(long int iterationNum);
long double Euler(long int iterationNum);
private:
long long int fact(int f);
};
- 为了让输出尽可能的高,用了最大的long double来定义函数返回值。
- iterationNum 是迭代次数,为了适应未来可能的超大迭代次数,这里用了long型(虽然在前期这看起来又傻效率又低)
接下来就是具体实现:
long double Algorithm::Vieta(long int iterationNum)
{
long double pi = sqrt(0.5);
for(int i=0;i<iterationNum;i++){
pi *= sqrt(0.5 + 0.5 * pi_2);
}
return 2/pi;
}
long double Algorithm::Leibniz(long int iterationNum)
{
long double pi = 0;
long double d = 1.0;
for(int i=0;i<iterationNum;i++){
pi += (1.0/d) * pow(-1,i);
d += 2.0;
}
return 4*pi;
}
long double Algorithm::Newton(long int iterationNum)
{
long double pi = 0;
for(int i=0;i<iterationNum;i++){
pi += 1.0 / (pow(4,i) * fact(1+2*i));
}
return 3*pi;
}
long double Algorithm::Newton_Leibniz(long int iterationNum)
{
long double pi = 3.0;
long long int j;
for(int i=1;i<iterationNum;i++){
j = 2*i;
pi += (4.0 / (j*(j+1)*(j+2))) * pow(-1,i-1);
}
return pi;
}
long double Algorithm::Sharp(long int iterationNum)
{
long double pi = 0;
for(int i=0;i<iterationNum;i++){
pi += (1.0 / ((1+2*i) * pow(3,i))) * pow(-1,i);
}
pi *= sqrt(1.0/3);
return 6*pi;
}
long double Algorithm::Euler(long int iterationNum)
{
long double pi = 0;
for(int i=1;i<iterationNum;i++){
pi += 1.0/(i*i);
}
return sqrt(pi*6);
}
long long int Algorithm::fact(int f)
{
if(f <= 1){
return 1;
}
long long int r = 1;
for(int i=1;i<=f;i++){
r *= i;
}
return r;
}
这里需要说明一下,在Newton_Leibniz()这个函数中,我使用了一个临时变量j来存储临时乘法结果,而不是直接使用i来构造连续乘法。这是因为c会将乘法结果放置在当前参数类型下的一个临时变量中,也就是说,int * int = int,然而int的上界很小,当i稍大一些时,我们的函数就会有溢出的问题,因此使用了一个long long 型的变量来解决这个问题。
突然想到能否使用static_cast进行显式转型解决,试试看。。。
然而并不好用
该系列在ANC课程结束的那一瞬间进入墓地,等待重启。。。