有趣的PI运算

! 没写完,先别看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课程结束的那一瞬间进入墓地,等待重启。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值