回 帖 发 新 帖 刷新版面

主题:TP7下计算圆周率至小数点后10000位

第一次来到本论坛,没什么好贴的,贴一个很久以前我自己编的程序。这个程序在tp7下至少能输出圆周率的小数点后10000位。
你可以自己改变dn的值试试。


program spi;
uses crt;
{ pi=16acrtg(1/5)-4arctg(1/239)   }
{ pi/4=1/1*(20/25-239/57121)-1/3(20/25^2-239/57121^2)+... }
label ext,ext2;
const
      dn=2502;
var
   i,ip,c:integer;
   k:longint;
   a,b,sum:array[1..dn] of integer;

procedure oupt;
var i:integer;
    k:longint;

procedure testk;
var
   ch:char;
begin
     if k mod 10=0 then write(' ');
     if (k mod 50=0) and (k mod 1000<>0) then
              writeln(':',k:8);
     if k mod 1000<>0 then exit;
     writeln(':',k:8,'  Press any key');
     ch:=readkey;
     writeln;

end;

begin
   clrscr;  k:=0;
   writeln('PI=');
   writeln(sum[1],'.');
   for i:=2 to dn do
     begin
       write(sum[i] div 1000);  k:=k+1; testk;
       write(sum[i] div 100 mod 10); k:=k+1; testk;
       write(sum[i] div 10 mod 10 ); k:=k+1; testk;
       write(sum[i] mod 10);  k:=k+1; testk;
     end;
   writeln; writeln;
   writeln('Programmed by j.t.chang.');

end;

procedure m_div(k:longint);
var
    i:integer;
    r1,c:longint;
begin
   c:=0;
   for i:=ip to dn do
     begin
        r1:=c*10000+a[i];
        a[i]:=r1 div k;
        c:=r1 mod k;
     end;
end;
procedure m_div2(k:longint);
var
    i:integer;
    r1,c:longint;
begin
   c:=0;
{   for i:= ip-1 downto 1 do  b[i]:=0; }
   for i:=ip to dn do
     begin
        r1:=c*10000+a[i];
        b[i]:=r1 div k;
        c:=r1 mod k;
     end;
end;


procedure sum_add;
var
   i:integer;
   r1,c:longint;
begin
   c:=0;
   for i:= dn downto ip do
    begin
        r1:=c+b[i]+sum[i];
        if r1>9999 then
          begin
              sum[i]:=r1 - 10000;
              c:=1;
          end
         else
           begin
             sum[i]:=r1;
             c:=0;
           end;
    end;
   if c=0 then exit;
   i:=ip-1;
   while c>0 do
      begin
         if i=1 then
            begin
               sum[1]:=c+sum[1];
               exit;
            end
         else
            begin
              r1:=c+sum[i];
              if r1>9999 then
                begin
                    sum[i]:=r1 - 10000;
                    c:=1;
                 end
               else
                  begin
                    sum[i]:=r1;
                    c:=0;
                  end;
            end;
          i:=i-1;
      end;
end;
procedure sum_sub;
var
   i:integer;
   r1,c:longint;
begin
   c:=0;
   for i:= dn downto ip do
    begin
        r1:=c-b[i]+sum[i];
        if r1<0 then
          begin
              sum[i]:=r1+10000;
              c:=-1;
          end
         else
           begin
             sum[i]:=r1;
             c:=0;
           end;
    end;
   if c=0 then exit;
   i:=ip-1;
   while c<0 do
      begin
         if i=1 then
            begin
               sum[1]:=c+sum[1];
               exit;
            end
         else
            begin
               r1:=c+sum[i];
               if r1<0 then
                 begin
                    sum[i]:=r1+10000;
                    c:=-1;
                 end
              else
                  begin
                     sum[i]:=r1;
                     c:=0;
                  end;
            end;
          i:=i-1;
      end;
end;

procedure proc;
var
  r1,c:longint;
  i:integer;
begin
    c:=0;
    for i:=dn downto 1 do
      begin
        r1:=1;
        r1:=c+r1*sum[i]*4;
        if r1>9999 then
          begin
             sum[i]:=r1 mod 10000;
             c:=r1 div 10000;
          end
        else
           begin
             sum[i]:=r1;
             c:=0;
           end;
      end;

end;

begin
   clrscr;
   for i:=1 to dn do sum[i]:=0;
   a:=sum;
   a[1]:=20;
   k:=1;
   ip:=1;
   c:=1;
   repeat
      gotoxy(1,1);
      write(ip:8);
      i:=ip;
      while  a[i]=0 do
        begin
            i:=i+1;
            if i>dn then goto ext;
        end;
      ip:=i;
      m_div(25);
      m_div2(k);
      if c=1 then  sum_add
       else sum_sub;
      k:=k+2;
      c:=-c;
   until false;
ext:
   for i:=1 to dn do a[i]:=0;
   a[1]:=239;
   b:=a;
   k:=1;
   ip:=1;
   c:=-1;
   repeat
      gotoxy(1,1);
      write(ip:8);
      i:=ip;
      while  a[i]=0 do
        begin
            i:=i+1;
            if i>dn then goto ext2;
        end;
      ip:=i;
      m_div(57121);
      m_div2(k);
      if c=1 then  sum_add
       else sum_sub;
      k:=k+2;
      c:=-c;
   until false;
ext2:
      proc;
      gotoxy(1,10);
      oupt;
end.

回复列表 (共8个回复)

沙发

运行中出错!

板凳

To:hs3180
出错?你的CRT单元没有打补丁是不是?

3 楼

我记得圆周率不是这样求的

4 楼

那个补丁谁贴下?thx

5 楼

难得有人还肯搞π值计算~~~!!!
这是我那全国科技创新奖的论文《π值计算的新算法》的一部分,愿与你探讨!
我的程序可以算到5亿位以上。



第二部分  计算π程序的算法核心

基于近代数学理论发展的突飞猛进,尤其是模型式理论和无穷级数理论的发展,π值的计算逐步实现了高精度、高速度。现在我们应用计算机进行π值计算,已逐渐形成了基于两种不同算法理论核心的程序,下面列出现今最具代表性的两个软件的资料:

软件名称    作者    使用的算法    基于的算法理论核心
Superπ    日本东京大学金田康正研究室    Borwein四次迭代    无穷级数理论
PiFast    Xavier Gourdon    Ramanujan    模型式理论

1.Superπ的作者金田康正在π值计算方面很有建树他选择Borwein四次迭代法作为Superπ的核心算法有着他的道理,下面我们研究Borwein四次迭代算法:
  (1)公式
       初值:

       重复计算:
              
              
       最后计算:
             π
这个算法由Jonathan Borwein和Peter Borwein于1985年发表。

  (2)程序结构
       
Step1:
    a = 1
    b = 1 / sqrt( 2 )
    t = 1 / 4
    x = 1
    Step2:
    y = a
    a = ( a + b ) / 2
    b = sqrt( b *y )
    t = t - x *( y - a )^2
    x = 2 *x
    Step3:
   π= (a+b) ^2

   (3)算法的优点与缺点
    由于此公式四次收敛于π,每迭代一次可得到二位数位精度,在π值计算约前3000万位时相比其他算法优势很大。但在3000万位后的计算,由于迭代规模趋向巨大,所用时间呈指数级增长,且规模超出一般家用计算机的计算能力。因此,现在最著名的π值计算软件Superπ的作者清醒地认识到了这一点,将Superπ的最高精度限定在3355万位。
    是不是说家用计算机上的π值计算工作只能进行到3000多万位呢?这是错误的,在模型式理论的基础下,家用机上的π值计算已几乎没有了最大精度的限制(但这也就意味着最大计算时间没有了限制)。


2.目前PC机上流行的精度最高的的圆周率计算程序是PiFast。它除了计算圆周率,还可以计算e和 。PiFast可以利用磁盘缓存,突破物理内存的限制进行超高精度的计算,最高计算位数可达240亿位,并提供基于Fabrice Bellard公式的验算功能。
    PiFast使用了基于模型式理论的Ramanujan算法以及将其改进后的Chudnovsky算法。

   (1)公式
Ramanujan公式:




这个公式每计算一项可以得到8位的十进制精度。
    
    


Chudnovsky公式:



这个公式每计算一项可以得到15位的十进制精度。

(2)程序结构
用这两个公式计算π值只需套用公式即可,故此部分省略。
若涉及到优化,则将等式右边分为两部分:                                                                   



     
                                        
   (3)算法的优点与缺点
    运用此公式计算π值,突破了π值计算随位数增加运算时间呈指数级增长的态势,实现了线性增长,在理论上将π值计算到了无限位。但此算法在任何一个精度运算量都很大,也就是说,原来用Borwein四次迭代计算1.6万位约需0.5s,而运用Chudnovsky算法则远超过这个数字。
经过以上分析后,作者发现,基于无穷级数理论的计算公式(Borwein四次迭代)在计算π值前3000万位上是不二之选,这一点已有充分的资料证明(请访问Kanada的主页)。但是要想在计算机上将π值计算到上亿甚至10亿位,用什么算法呢?作者便有了一个大胆的设想:在计算π值前3000万位(以3000万位作为分界还有待考证)时使用Borwein四次迭代法;3000万位后使用基于模型式理论的算法。
    由David Bailey,Peter Borwein,Simon Plouffe于1995年共同发表的Bailey-Borwein-Plouffe(简称BBP)算法帮助作者实现了这个设想:


它打破了传统的圆周率的算法,可以计算圆周率的任意第n位,而不用计算前面的n-1位。这为圆周率的分布式计算提供了可行性。

    算法的程序实现并不难,但是有了合适的公式,还有很重要的高精度计算问题。人们在高精度计算方面已经作了很多研究,而现今的水平也远非作者所能及。因此,作者在经过考虑后,决定直接调用由Floating Point Software开发的高精度函数计算库ExacMath。(详见http://www.ftpsoftware.com)

第三部分  使用何种语言编写程序

    算法有了,程序用什么语言编写?若语言选择得不好,会直接影响到程序速度。因此,作者对现今几种编程软件的大规模数据处理能力进行了测试,使用的是e值计算的公式:
                                 
    用此公式将e值计算到了10万位并对比所用时间:

编程软件    Turbo Pascal 7.0    C++    Delphi    汇编
耗时    1.51s    1.50s    1.48s    1.46s
注:仅供参考
    由此,作者最终使用了汇编语言进行了程序制作。


第四部分  新算法与PiFast、Superπ的比较

    我们在一台Pentium4 1.7Ghz/512M的计算机上对三个程序进行对比测试,测试结果如下表:
    1.6万位    26万位    104万位    838万位    3355万位    5亿位
Superπ    <0.1s    13s    33.42s    1min42s    1h52min    不可计算
PiFast    0.9s    16s    51s    2min11s    1h42min    12h
新算法    <0.1s    13s    33.55s    1min45s    1h45min    12h

显然,Superπ在运算π值3000位以前时较有优势,PiFast与其相差很远。由于新算法在前3000万位使用了与Superπ相同的算法,仅因作者水平有限而与Superπ有了一点差距,但这不影响新算法的优势。可以说,新算法是兼有Superπ与PiFast两种算法的优点。


参考文献
[1] 《π值计算的若干问题》      李学武            天津师范大学学报
[2] 《π的奥秘》                (日)堀场芳数       科学出版社

6 楼

公式全是图片,发不上来~~~

7 楼

to 孤风男孩
呵呵!我当然搞不过!不过,编程的东西就要自己练练。我是试试自已动手编编看。

8 楼

王欣欣:计算PI的方法有很多,不止一种,你可以上有关的网站查查!!!

我来回复

您尚未登录,请登录后再回复。点此登录或注册