易码技术论坛

 找回密码
 加入易码
搜索
查看: 144365|回复: 7

[转帖]只用30条语句计算圆周率π值, 精确到小数点后 10000 位

[复制链接]
发表于 2005-9-4 17:09:00 | 显示全部楼层
哇,强!
慢耶
发表于 2005-10-23 16:42:00 | 显示全部楼层
yun a
发表于 2006-1-13 11:01:00 | 显示全部楼层
不知用LAVA能怎么算出π??
发表于 2006-1-13 12:02:00 | 显示全部楼层
下面是LavaX计算π的程序



  1. #define ENTER_KEY 0x0d
  2. #define ESC_KEY 0x1b

  3. int f[2801];
  4. char numberc[]="bnmghjtyu";

  5. char to_number(char c)
  6. {
  7. int i;
  8. for (i=0;i<9;i++)
  9.   if (c==numberc[i]) {
  10.    c=i+'1';
  11.    break;
  12.   }
  13. return c;
  14. }

  15. int get_num(int bits)
  16. {
  17. int i,t,d;

  18. t=0;
  19. i=0;
  20. for (;;) {
  21.   d=to_number(getchar());
  22.   if (d>='0' && d<='9' && i<bits) {
  23.    putchar(d);
  24.    t=t*10+(d&0xf);
  25.    i++;
  26.   } else if (d==ENTER_KEY && i)
  27.    break;
  28. }
  29. return t;
  30. }

  31. void main()
  32. {  
  33. int t;
  34. long b,c,d,e,g;

  35. printf("请输入位数:");
  36. c=((get_num(3)+3)&0xfffc)*14/4;
  37. if (c>2800) c=2800;
  38. putchar('\n');
  39. for(;b-c;) f[b++]=10000/5;
  40.     for(;;) {
  41.   d=0;
  42.   if (!(g=c<<1)) break;
  43.   b=c;
  44.   for (;;) {
  45.    d=d+f[b]*10000;
  46.    f[b]=d%--g;
  47.    d=d/g--;
  48.    if (--b==0) break;
  49.    d=d*b;
  50.   }
  51.   c=c-14;
  52.   t=e+d/10000;
  53.   if (t<10) printf("000%d",t);
  54.   else if (t<100) printf("00%d",t);
  55.   else if (t<1000) printf("0%d",t);
  56.   else printf("%d",t);
  57.   e=d%10000;
  58.   if (Inkey()==ESC_KEY) exit(0);
  59. }
  60. getchar();
  61. }

复制代码

发表于 2006-1-13 12:46:00 | 显示全部楼层
第52行有问题??
发表于 2006-1-13 13:37:00 | 显示全部楼层
代码帖上去就走样了。

看下面的:

[upload=txt]viewFile.asp?ID=5006[/upload]

10381_27365_5006.txt

1 KB, 下载次数: 441

发表于 2006-1-13 23:31:00 | 显示全部楼层
谢谢,找了好久
 楼主| 发表于 2005-9-3 09:40:24 | 显示全部楼层 |阅读模式
大家都知道π=3.1415926……无穷多位, 历史上很多人都在计算这个数, 一直认为是一个非常复杂的问题。现在有了电脑, 这个问题就简单了。
电脑可以利用级数计算出很多高精度的值, 有关级数的问题请参考《高等数学》

因为计算π值, 而这个公式是计算π/2的, 我们把它变形:
π = 2 + 2/3 + 2/3*2/5 + 2/3*2/5*3/7 + ...

------------
对于级数, 我们先做个简单测试, 暂时不要求精度:
用 C++ Builder 新建一个工程, 在 Form 上放一个 Memo1 和 一个 Button1, 在 Button1 的 OnClick 事件写:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  double x=2, z=2;
  int a=1, b=3;
  while(z>1e-15)
  {
    z = z*a/b;
    x += z;
    a++;
    b+=2;
  }
  Memo1->Text = AnsiString().sprintf("Pi=%.13f", x);
}
按Button1在Memo1显示出执行结果:
Pi=3.1415926535898

----------
这个程序太简单了, 而且 double 的精度很低, 只能计算到小数点后 10 几位。
把上面的程序改造一下, 让它精确到小数点后面 1000 位再测试一下:
在 Form 上再放一个按钮 Button2, 在这个按钮的 OnClick 事件写:


  1. void __fastcall TForm1::Button2Click(TObject *Sender)
  2. {
  3.   const ARRSIZE=1010, DISPCNT=1000; //定义数组大小,显示位数
  4.   char x[ARRSIZE], z[ARRSIZE]; //x[0] x[1] . x[2] x[3] x[4] .... x[ARRSIZE-1]
  5.   int a=1, b=3, c, d, Run=1, Cnt=0;
  6.   memset(x,0,ARRSIZE);
  7.   memset(z,0,ARRSIZE);
  8.   x[1] = 2;
  9.   z[1] = 2;
  10.   while(Run && (++Cnt<200000000))
  11.   {
  12.     //z*=a;
  13.     d = 0;
  14.     for(int i=ARRSIZE-1; i>0; i--)
  15.     {
  16.       c = z[i]*a + d;
  17.       z[i] = c % 10;
  18.       d = c / 10;
  19.     }
  20.     //z/=b;
  21.     d = 0;
  22.     for(int i=0; i<ARRSIZE; i++)
  23.     {
  24.       c = z[i]+d*10;
  25.       z[i] = c / b;
  26.       d = c % b;
  27.     }
  28.     //x+=z;
  29.     Run = 0;
  30.     for(int i=ARRSIZE-1; i>0; i--)
  31.     {
  32.       c = x[i] + z[i];
  33.       x[i] = c%10;
  34.       x[i-1] += c/10;
  35.       Run |= z[i];
  36.     }
  37.     a++;
  38.     b+=2;
  39.   }
  40.   Memo1->Text = AnsiString().sprintf("计算了 %d 次\r\n",Cnt);
  41.   Memo1->Text = Memo1->Text + AnsiString().sprintf("Pi=%d%d.\r\n", x[0],x[1]);
  42.   for(int i=0; i<DISPCNT; i++)
  43.   {
  44.     if(i && ((i%100)==0))
  45.     Memo1->Text = Memo1->Text + "\r\n";
  46.     Memo1->Text = Memo1->Text + (int)x[i+2];
  47.   }
  48. }

复制代码

按 Button2 执行结果:
Pi=03.
1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196
4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273
7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094
3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912
9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132
0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235
4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859
5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303
5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989

-------------
这下心理有底了, 是不是改变数组大小就可以计算更多位数呢?答案是肯定的。
如果把定义数组大小和显示位数改为:
const ARRSIZE=10100, DISPCNT=10000; //定义数组大小,显示位数
执行结果精度可达 10000 位:
Pi=03.
1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196
4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273
7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094
3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912
9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132
0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235
4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859
5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303
5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989
3809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151
... 限于篇幅, 这里就省略了, 还是留给你自己来算吧!
5020141020672358502007245225632651341055924019027421624843914035998953539459094407046912091409387001
2645600162374288021092764579310657922955249887275846101264836999892256959688159205600101655256375678

提高精度的原理:
以上程序的原理是利用数组把计算结果保存起来, 其中数组每一项保存10进制数的一位,
小数点定位在数组第1个数和第二个数之间, 即小数点前面2位整数, 其余都是小数位。
利用电脑模拟四则运算的笔算方法来实现高精度的数据计算,没想到最原始的方法竟然是精度最高的。

[em05][em05]




您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2025-8-24 18:29 , Processed in 0.016496 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表