圆周率PI的高精度计算(C/C++)

某次碰到pi,想用编程打印出它的比较多的有效位(至少比背的要多)。

开始考虑到 pi/4 = arctan(1)

arctan(x)展成多项式 arctan(x) = (1/1!)x - (1/3)(x^3) + (1/5)(x^5) - ....

所以有 pi/4 = 1 - 1/3 + 1/5 - 1/7 + .....

但是上式后面的式子收敛太慢了,编程很难求到很多的有效位,

而后查到Machin公式 pi/4 = 4arctan(1/5) - arctan(1/239),这个公式可以自己证明一下(忘的差不多了,涂了半天才算对)

这样泰勒展开式收敛很快,我就是照着这个公式编程的,代码如下

 

#include <stdio.h>
#include <string.h>
#include <malloc.h>

#define KS_MIN(a, b) ((a)<(b)?(a):(b))
#define KS_MAX(a, b) ((a)>(b)?(a):(b))

#define BITS 20000

typedef struct BigInt
{
    int L;
    int *d;
    BigInt(){
        L = 1;
        d = (int*)malloc((BITS + 16)*sizeof(int));
        d[0] = 0;
    }
    ~BigInt(){ free(d); }

}BigInt;

// out = in / x;
void division(BigInt &out, BigInt &in, int x)
{    
    out.L = in.L;
    memset(out.d, 0, out.L*sizeof(int));
    int i, s = 0;
    for (i = in.L-1; i >= 0; i--)
    {
        s = s*10 + in.d[i];
        out.d[i] = s/x;
        s %= x;
    }
    for (i = out.L-1; i >= 0; i--)
    {
        if (out.d[i]) break;
    }
    out.L = i+1;
    if (out.L == 0) out.L++;
}

// a += b;
void addequal(BigInt &a, BigInt &b)
{
    int len = KS_MAX(a.L, b.L)+1;
    memset(a.d+a.L, 0, (len-a.L)*sizeof(int));
    a.L = len;
    int i;
    for (i = 0; i < b.L; i++)
        a.d[i] += b.d[i];
    for (i = 0; i < a.L-1; i++)
    {
        if (a.d[i] > 9){
            a.d[i+1]++;
            a.d[i] -= 10;
        }
    }
    for (i = a.L-1; i >= 0; i--)
    {
        if (a.d[i]) break;
    }
    a.L = i+1;
    if (a.L == 0) a.L++;
}

// a -= b;
void subequal(BigInt &a, BigInt &b)
{    
    int i;
    for (i = 0; i < b.L; i++)
        a.d[i] -= b.d[i];
    for (i = 0; i < a.L-1; i++)
    {
        if (a.d[i] < 0){
            a.d[i+1]--;
            a.d[i] += 10;
        }
    }
    for (i = a.L-1; i >= 0; i--)
    {
        if (a.d[i]) break;
    }
    a.L = i+1;
    if (a.L == 0) a.L++;
}

// a *= k
void mulequal(BigInt &a, int k)
{
    int i;
    for (i = 0; i < a.L; i++)
        a.d[i] *= k;
    memset(a.d+a.L, 0, 12*sizeof(int));
    a.L += 12;
    for (i = 0; i < a.L-1; i++)
    {
        if (a.d[i] > 9){
            a.d[i+1] += a.d[i]/10;
            a.d[i] %= 10;
        }
    }
    for (i = a.L-1; i >= 0; i--)
    {
        if (a.d[i]) break;
    }
    a.L = i+1;
    if (a.L == 0) a.L++;
}

void BigIntCopy(BigInt &dst, BigInt &src)
{
    dst.L = src.L;
    memcpy(dst.d, src.d, dst.L*sizeof(int));
}

void argtanx(BigInt &out, int x, int digit)
{
    BigInt a, b;    
    a.L = digit+1;    
    memset(a.d, 0, (a.L-1)*sizeof(int));
    a.d[a.L-1] = 1;
    division(b, a, x);
    BigIntCopy(a, b);  
    BigIntCopy(out, b);   
    int i = 3, xx = x*x, p = -1;
    while (1)
    {
        division(b, a, xx);
        BigIntCopy(a, b);
        division(b, a, i);
        if (b.L == 1 && b.d[0] == 0)
            break;
        if (p < 0) subequal(out, b);
        else addequal(out, b);
        p *= -1;
        i += 2;
    }
}

void print(BigInt &a)
{
    printf("%d.", a.d[a.L-1]);
    int i;
    int low = a.L > 200 ? a.L-200 : 0; // 不打算全部打印出来
    for (i = a.L-2; i >= low; i--)
        printf("%d", a.d[i]);
    printf("\n");
}

int main(int argc, char *argv[])
{    
    BigInt a, b;
    argtanx(a, 5, BITS);
    argtanx(b, 239, BITS);
    mulequal(a, 16);
    mulequal(b, 4);
    subequal(a, b);    
    print(a);
    return 0;
}

///* pi/4 = 4*arctan(1/5) - arctan(1/239) */


设要算的有效位数为N,那么上面时间复杂度大概O(N^2),所有10000位在几秒钟内应该能算出来

 

 然后某次网上看到别人写的代码(稍微修改过)

#include <stdlib.h> 
#include <stdio.h> 

#define BITS 2000
int a=10000,b,c=BITS*7/2,d,e,f[BITS*7/2+1],g; 

int main() 
{   
	for(;b-c;) 
		f[b++]=a/5; 
	for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a) 
		for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);     
	//getchar();
	return 0;
} 


太简短了!!!然后结果和我上面的对照过,是一致。

从代码上看时间复杂度也是O(N^2),真实测时速度比我上面的代码要快一些。

还好时间复杂度一致,不至于让我过分自悲,然后看了半天也不明白它这个是用什么原理设计的。

 

而后又查了一些pi的公式

http://zhan.renren.com/52faming?gid=3602888498032257169&checked=true

 

拉马努金公式 

 

丘德诺夫斯基简化版公式

 

 

等等,据说上面很多公式(如丘德诺夫斯基)计算pi很快,我其实不太理解怎么处理那个根号。。。

pi的有效位已经到 万亿位级别

还有一个bbp的关于pi的.....

 

好吧,我只能说我真的是过分渺小了。。。。。。

 

 

你可能感兴趣的:(圆周率PI的高精度计算(C/C++))