计算圆周率 Pi (π)值, 精确到小数点后 10000 位 只需要 30 多句代码!
2013-11-06 21:44
411 查看
原文地址http://www.cppfans.com/articles/basecalc/c_pi_10000.asp by: Victor Chen
大家都知道π=3.1415926……无穷多位, 历史上很多人都在计算这个数, 一直认为是一个非常复杂的问题。现在有了电脑, 这个问题就简单了。
电脑可以利用级数计算出很多高精度的值, 有关级数的问题请参考《高等数学》,以下是比较有名的有关π的级数:
其中有些计算起来很复杂, 我们可以选用第三个, 比较简单, 并且收敛的非常快。
因为计算π值, 而这个公式是计算π/2的, 我们把它变形:
π = 2 + 2/3 + 2/3*2/5 + 2/3*2/5*3/7 + ...
对于级数, 我们先做个简单测试, 暂时不要求精度:
用 C++ Builder 新建一个工程, 在 Form 上放一个 Memo1 和 一个 Button1, 在 Button1 的 OnClick 事件写:
按Button1在Memo1显示出执行结果:
Pi=3.1415926535898
这个程序太简单了, 而且 double 的精度很低, 只能计算到小数点后 10 几位。
把上面的程序改造一下, 让它精确到小数点后面 1000 位再测试一下:
在 Form 上再放一个按钮 Button2, 在这个按钮的 OnClick 事件写:
按 Button2 执行结果:
这下心理有底了, 是不是改变数组大小就可以计算更多位数呢?答案是肯定的。
如果把定义数组大小和显示位数改为:
const ARRSIZE=10100, DISPCNT=10000; //定义数组大小,显示位数
执行结果精度可达 10000 位:
提高精度的原理:
以上程序的原理是利用数组把计算结果保存起来, 其中数组每一项保存10进制数的一位,
小数点定位在数组第1个数和第二个数之间, 即小数点前面2位整数, 其余都是小数位。
利用电脑模拟四则运算的笔算方法来实现高精度的数据计算,没想到最原始的方法竟然是精度最高的。
大家都知道π=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 事件写:
void __fastcall TForm1::Button2Click(TObject *Sender) { const ARRSIZE=1010, DISPCNT=1000; //定义数组大小,显示位数 char x[ARRSIZE], z[ARRSIZE]; //x[0] x[1] . x[2] x[3] x[4] .... x[ARRSIZE-1] int a=1, b=3, c, d, Run=1, Cnt=0; memset(x,0,ARRSIZE); memset(z,0,ARRSIZE); x[1] = 2; z[1] = 2; while(Run && (++Cnt<200000000)) { //z*=a; d = 0; for(int i=ARRSIZE-1; i>0; i--) { c = z[i]*a + d; z[i] = c % 10; d = c / 10; } //z/=b; d = 0; for(int i=0; i<ARRSIZE; i++) { c = z[i]+d*10; z[i] = c / b; d = c % b; } //x+=z; Run = 0; for(int i=ARRSIZE-1; i>0; i--) { c = x[i] + z[i]; x[i] = c%10; x[i-1] += c/10; Run |= z[i]; } a++; b+=2; } Memo1->Text = AnsiString().sprintf("计算了 %d 次\r\n",Cnt); Memo1->Text = Memo1->Text + AnsiString().sprintf("Pi=%d%d.\r\n", x[0],x[1]); for(int i=0; i<DISPCNT; i++) { if(i && ((i%100)==0)) Memo1->Text = Memo1->Text + "\r\n"; Memo1->Text = Memo1->Text + (int)x[i+2]; } }
按 Button2 执行结果:
Pi=03.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989
这下心理有底了, 是不是改变数组大小就可以计算更多位数呢?答案是肯定的。
如果把定义数组大小和显示位数改为:
const ARRSIZE=10100, DISPCNT=10000; //定义数组大小,显示位数
执行结果精度可达 10000 位:
Pi=03.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151 ... 限于篇幅, 这里就省略了, 还是留给你自己来算吧! 50201410206723585020072452256326513410559240190274216248439140359989535394590944070469120914093870012645600162374288021092764579310657922955249887275846101264836999892256959688159205600101655256375678
提高精度的原理:
以上程序的原理是利用数组把计算结果保存起来, 其中数组每一项保存10进制数的一位,
小数点定位在数组第1个数和第二个数之间, 即小数点前面2位整数, 其余都是小数位。
利用电脑模拟四则运算的笔算方法来实现高精度的数据计算,没想到最原始的方法竟然是精度最高的。
相关文章推荐
- 计算圆周率 Pi (π)值, 精确到小数点后 10000 位 只需要 30 多句代码
- 如何计算圆周率 Pi (π)值, 精确到小数点后 10000 位 只需要 30 多句代码!
- 计算圆周率 Pi (π)值, 精确到小数点后 10000 位
- 计算圆周率 Pi (π)值, 精确到小数点后 10000 位(C语言)
- Python计算开方、立方、圆周率,精确到小数点后任意位
- 精确计算PI小数点后800位小数
- 用VB计算PI精确数值到30000位的程序代码。
- Python计算开方、立方、圆周率,精确到小数点后任意位的方法
- 精确计算PI小数点后800位小数
- C++精确计算代码执行时间精度微秒级
- 南北朝时,我国数学家祖冲之首先把圆周率值计算到小数点后六位,比欧洲早了1100年!
- 精确计算代码执行时间
- iOS NSDecimalNumber精确数值计算以及小数点后精确保留2位数字
- 有一个很大的整数list,需要求这个list中所有整数的和,写一个可以充分利用多核CPU的代码,来计算结果(转)
- 精确计算代码运行时间
- 1、编写程序,分别用二分法和牛顿迭代法求解方程x3 – 3x – 1 = 0在x = 2附近的实根,要求计算精确到小数点后七位数字为止,并将求出的近似结果与理论值2cos20 相比较,二分法的初始迭代
- 四行代码计算圆周率800位的怪异程序(转)
- iOS NSDecimalNumber精确数值计算以及小数点后精确保留2位数字
- 精确计算代码执行时间
- 精确计算TFS中新增以及更改的代码行数