plp626 发表于 2011-4-22 11:10:32

一个计算圆周率任意精度的spigot算法研究

最初接触到这算法是论坛的这个帖子:
http://bbs.emath.ac.cn/viewthread.php?tid=1935
网上的那段C代码在这里贴下long a=10000,b,c=2800,d,e,f,g;
main(){for(;b-c;)f=a/5;
for(;d=0,g=c*2;c -=14,printf("%.4d",e+d/a),e=d%a)
for(b=c; d+=f*a,f=d%--g,d/=g--,--b; d*=b);}
用到的级数是pi/2= sum{k!/(2*k-1)!!,k=0,1,2,...}两年前我把它用批处理代码改写后,让它可以计算任意精度。@echo off&title 计算圆周率任意精度
:: windows系统直接保存为pi.bat,双击运行,默认计算100位精度
:: 命令行下执行,第一个参数(整数)为圆周率小数点的位数。
setlocal enabledelayedexpansion
if not %1.==. (set c=%1) else set c=100
set/a c=(c*100/3)+70,cc=c/10
for /l %%a in (1 1 %cc%)do set/a f_%%a=2000
for /l %%a in (%c% -132 100)do (set/a n=%%a/10,m=2*n-1
   set/a "d=f_!n!*10000,f_!b!=d%%m,d=d/m,n-=1"
   for /l %%b in (!n! -1 1)do (set/a n=%%b,m=2*n-1
      set/a "d=d*n+f_!n!*10000,f_!n!=d%%m,d=d/m,n-=1"
   )
   set/a "an=e+d/10000,e=d%%10000"
   if !an! lss 1000 set an=000!an!
   set/p=!an:~-4!<nul
)
pause因为网上流传的那段的C代码没有任何可读性,消化那段C代码花了我好几个晚上的闲暇时间,但当时仅是为了在一个bat论坛娱乐,一点注释也没写。现在自己也是一点看不懂了。

对这样所谓的spigot算法,我仅仅知道这个代码,这对时间又对它感兴趣了,我想问,有没有计算整数开方的此类spigot算法,因为它无需建立大数据类型,实现起来很简洁。

我想对这类算法做深入的研究,不知论坛是否已有讨论过,或者有这方面的学习资料也好。

提前谢谢各位回帖。

zeroieme 发表于 2011-4-22 12:13:28

建基在BBP公式上的,而BBP公式还没有理论上的突破。

http://zh.wikipedia.org/zh/%E8%B4%9D%E5%88%A9%EF%BC%8D%E6%B3%A2%E5%B0%94%E6%B8%A9%EF%BC%8D%E6%99%AE%E5%8A%B3%E5%A4%AB%E5%85%AC%E5%BC%8F

我也幻想所有基本超越函数能BBP化,这样在超越函数运算能转化到多项式计算。

liangbch 发表于 2011-4-22 20:12:26

1楼的代码太强了,强的我几乎完全看不懂,能否提供一些关于Dos批处理语法方面的参考资料,也好让我辈学习一下。

〇〇 发表于 2011-4-23 10:41:10

nice job

plp626 发表于 2011-4-23 15:50:08

1楼的代码太强了,强的我几乎完全看不懂,能否提供一些关于Dos批处理语法方面的参考资料,也好让我辈学习一下。
liangbch 发表于 2011-4-22 20:12 http://bbs.emath.ac.cn/images/common/back.gif

版主这样的 回复 有点让我不好意思了,你的很多帖子我都跟不上思路,惭愧~~~

批处理方面的语法,你在cmd下输入help即可,然后就不断的help命令名(或者命令名/?),就可查看命令语法

如果嫌这样慢,想一次看完,cmd下粘贴如下代码,可以把他们全输出:pushd %temp%
(for /f %a in ('"help|findstr/b "')do help %a)>help.txt
start help.txt
popd因为代码页是默认中文的,而中文的翻译又有歧义,也许看英文语法更专业些:chcp 437
pushd %temp%
(for /f "skip=1" %a in ('"help|findstr/b "')do help %a)>help-english.txt
start help-english.txt
popd国内的批处理论坛,环境不好不说,版主的回复比较让人无语,新人去有时被“你怎么连这个都不会,”“你都是一年的会员了,怎么还问这个问题。。。”
这个外国批处理论坛很不错: www.dostips.com

至于这方面的资料,国内很少,非主流的东西,没有多少人写;有也只是些论坛的精华帖,但是确实不精华啊。还是少看了。

plp626 发表于 2011-4-23 15:51:03

1# plp626

一楼代码有一处笔误f_!n!=d%%m写成了f_!b!=d%%m,导致后面精度丢失;两年了现在才发现。

现在改过来了:@echo off&title 计算圆周率任意精度
setlocal enabledelayedexpansion
if not %1.==. (set c=%1) else set c=100
set/ac=c*100/3+70,cc=c/10,n=cc
for /l %%a in (1 1 !cc!)do set/af_%%a=2000
for /l %%a in (!c! -132 100)do (
   set/an=%%a/10,m=2*n-1,d=f_!n!*10000,d=d/m,n-=1
   for /l %%b in (!n! -1 1)do set/an=%%b,m=2*n-1,d=d*n+f_!n!*10000,f_!n!=d%%m,d=d/m,n-=1
   set/aan="e+d/10000,e=d%%10000
   if !an! lss 1000 set an=000!an!
   set/p=!an:~-4!<nul
)
pause
其实还可以直接粘贴在cmd下,这样更方便些
:: 粘贴本代码在cmd命令行下回车即可
cmd /Q/V: ON
set "c=200" :: 这里设置的是输出200位(含整数位3)
set/ac=c*100/3+70,cc=c/10,n=cc>nul
(for /l %a in (1 1 !cc!)do set/af%a=2000 >nul)&for /l %a in (!c! -132 100)do (
   set/an=%a/10,m=2*n-1,d=f!n!*10000,f!n!=d%m,d=d/m,n-=1 >nul
   for /l %b in (!n! -1 1)do set/an=%b,m=2*n-1,d=d*n+f!n!*10000,f!n!=d%m,d=d/m,n-=1 >nul
   set/aan=e+d/10000,e=d%10000 >nul
   if !an! lss 1000 set an=000!an!
   set/p=!an:~-4!<nul
)

-----------------------
报告一个论坛bug,我这里从editplus上粘贴代码到回复框,还没点击编辑帖子直接就回复了,并且是俩回帖

zeroieme 发表于 2011-4-23 16:51:54

批处理无疑可以处理很复杂的任务。毕竟是解释执行,不适合作数值计算。

mjs1wh 发表于 2011-4-23 17:02:18

看不懂批处理,能改个BASIC的吗

plp626 发表于 2011-4-24 08:47:19

本帖最后由 plp626 于 2011-4-24 11:26 编辑

因为所谓的spigot算法都是建立在 收敛级数 之上的,我想如何得到一个整数开方,开立方,或者开n次方的 spigot算法,就是找一个 通项相对简洁 的收敛级数。
找到一个资料,得知网上那个输出sqrt(2) 小数点2400位的4行C代码(还是一点看不懂,但还是和一楼一样的spigot算法)main(){int a=1000,b=0,c=1413,d,f,n=800,k;
for(;b<c;f=14);
for(;n--;d+=*f*a,printf("%.3d",d/a),*f=d%a)
for(d=0,k=c;--k;d/=b,d*=2*k-1)f=(d+=f*a)%(b=100*k);}基于如下公式:
sqrt(2)=7/{5*sqrt(1-1/50)}
用到的是这个麦克劳林级数:
1/(1-x)^n=1+nx+{n(n+1)}/{2!}x^2+...
受到这个启发,我们把它扩展一下;
给上面级数两边同乘以一个有理数q/p得到
q/p*(1/(1-x)^n)=q/p*(1+nx+{n(n+1)}/{2!}x^2+...)
我们令一个整数N的开m次方root{m}{N}为:
root{m}{N}=q/p*(1/(1-b/a)^{1/m}), -1<b/a<1
我们给他两边再做m次方得到
N={q^m*a}/{p^m*(a-b)}
为了收敛速度快和以后的通项简洁些,我们可以令b=1,a为正整数;
所以问题可以转化为求下面关于正整数a,p,q的不定方程(*):
a*q^m-(a-1)*N*p^m=0
这里N,m为正整数常数,p,q互质.

对于这个不定方程的解,我们取a较大者,p,q较小者;
这样便可以得到任意一个正整数N开m次方的spigot算法的级数:
root{m}{N}=q/p*(1/(1-1/a)^{1/m})
=q/p*(1+1/{ma}+1/{m(m+1)*2!}*1/{a^2}+...+1/{m(m+1)...(m+n-1)*n!}*1/a^n+...)
=q/p*(1+1/{ma}(1+1/{(m+1)a}(1+...1/{(m+n-1)a}(1+......))))


问题现在来了, 解(*)处的不定方程,并求出最佳解,难住了我,大家帮我看看,提前谢谢了。

plp626 发表于 2011-4-24 10:57:36

若不限定b=1,更一般的情况就是,解关于正整数a,p,q,非0整数b 的不定方程:
a*q^m-(a-b)*N*p^m=0
其中N,m为正整数常数,p,q互质,a,b互质,|b|<a
页: [1] 2 3 4 5 6 7 8
查看完整版本: 一个计算圆周率任意精度的spigot算法研究