1. 使用的公式:

    PI=2+1/3*(2+2/5*(2+3/7*(2+…(2+k/(k+1)*2)))….)))

    化简为迭代情况:

    • 初始时:PI=2
    • 循环迭代:
      • PI=PIi/(2i+1)+2
      • 其中i位迭代变量,从一个很大的数到1,只要这个数足够大,
      • 那么PI的精度就越高。

      公式来源于互联网,原始网址已经丢失,对此感到抱歉。

  2. 为了保证效率,高精度运算采用10000进制运算。

  3. 由于此高精度问题,不能乘以/除以一个比较大的数(乘法的结果不能大于31bit,除法的除数不能大于31bit,乘法相对容易解决,除法就比较麻烦),所以不能计算无限位的PI。

  4. 关于本程序处理极限的讨论

    迭代极限次数:107382; 最高精度:小数点后第32327位; 具体情况如下:

     …861893818959054203… (PI的值)
     …       |              (竖线标记了小数点后第32327位)
     …861893815             (运算结果)
    

    其实,这个程序的效率比较低了,即使没有处理极限,算下去也没有什么意义 所以这里不进行高精度算法修改了,要算更大精度的,最好去换PI的算法了。

  5. 迭代次数大概是要求精度位数的3.4倍。

  6. 细节:运算先做乘法,在做除法会造成精度严重损失(不论迭代多少次, 都只有750多位精度),猜想是余数处理问题,具体细节未深究,所以修改后的, 就先做除法,在做乘法。

  7. 确定本程序精度参考了SuperPI的运算结果。

#include <stdio.h>
#define T 330/*迭代次数,最大:107382*/
#define N 25
/*数组保存小数部分的长度,精度的四分之一,最大:32327/4=8081.75,也就是8082*/
/*试验表明,迭代330次算的PI小数点后的100位已经是精确的了*/

int main(){
	int PI[N+1]={0},i,j,k,t;
	PI[0]=2;/*初始化*/
	for(i=T;i;i--){
	/* PI/(2*i+1) */
		t=0;/*除法了,这里保存余数,初始当然是0*/
		k=2*i+1;/*要除以的数,见PI的公式*/
		for(j=0;j<=N;j++){
			PI[j]+=t*10000;/*被除数是上一位的余数乘以进制再加上这一位上的数*/
			t=PI[j]%k;/*保存这次运算的余数,供下次使用*/
			PI[j]/=k;/*这次运算的结果*/
		}

	/* PI*i */
		t=0;/*保存乘法进位,初始当然是0*/
		for(j=N;j>=0;j--){
			t+=PI[j]*i;/*上次的进位加上这次乘得的结果就是这次的值*/
			//if(t<0){printf("Overflown"); return 0;}/*运算超过精度限制了*/
			PI[j]=t%10000;/*本位只保存余数*/
			t/=10000;/*这里就是保存进位*/
		}
		//if(t)printf("Unexpected!n");
		/*如果成立了,也就是整数部分的结果大于10000了,明显是错误的。*/

	/* PI+2 */
		PI[0]+=2;
		/*加上2,由于整数2小数点后面是零,所以小数点后面的不参与运算了(不是废话么?)。*/
		//printf("%d %d.",i,PI[0]);int ii;
		//for(ii=1;ii<=N;ii++)printf("%.4d",PI[ii]);
		//printf("n");getchar(); /*一次次观察结果*/
	}
	printf("%d.n",PI[0]);/*第一位为整数部分*/
	for(i=1;i<=N;i++){
		printf("%.4d",PI[i]);/*%.4d输出结果占四位,而且,数值小要补零*/
		if(i%5==0)printf("n");/* 4*5=20 每20位输出作一行 */
	}
	printf("n");
	//getchar();
	return 0;
}