円周率πを100万桁まで計算するプログラムを作ってみました。super pi もどきです。ソースコードと解説を載せます。
ソースコードは80行程度の非常に短いものですが、このような簡単な実装でも最近のPCなら100万桁の円周率が一分も掛らず計算できます。
ソースコード
- /**
- * pi.cpp
- *
- * written by pyopyopyo at gmail dot com
- */
- #include <math.h>
- #include <gmpxx.h>
- #include <iostream>
- // N桁の円周率を計算
- #define N 100*100*100
- using namespace std;
- int
- main()
- {
- // N桁の数値計算に必要な精度を prec(bits) とすると
- //
- // prec = log2(10^N)
- // = N * log2(10)
- // 計算誤差を考えるのがめんどうなので,とりあえず(N+5)桁で計算してみる
- int prec = (N+5)*log2(10);
- mpf_set_default_prec(prec);
- fprintf(stderr, "prec:= %d bits\n", prec);
- const mpf_class two ("2.0");
- mpf_class a ("1.0");
- mpf_class b (a/sqrt(mpf_class("2.0")));
- mpf_class t (a);
- mpf_class x (a);
- mpf_div_ui(t.get_mpf_t(), t.get_mpf_t(), 4);
- mpf_class tmp(a);
- const int P = ceil(log2(N));
- for (int k=1; k<=P; ++k) {
- tmp = a;
- a = a + b;
- mpf_div_ui(a.get_mpf_t(), a.get_mpf_t(), 2);
- b = sqrt( tmp*b );
- tmp -= a;
- mpf_pow_ui(tmp.get_mpf_t(), tmp.get_mpf_t(), 2);
- t -= x * tmp;
- x *= two;
- }
- tmp = a + b;
- mpf_pow_ui(tmp.get_mpf_t(), tmp.get_mpf_t(), 2);
- tmp /= t;
- mpf_div_ui(tmp.get_mpf_t(), tmp.get_mpf_t(), 4);
- mp_exp_t expo;
- char *str = mpf_get_str(0, &expo, 10, N+1, tmp.get_mpf_t());
- for (int i=expo,count=1; i<N; i+=10, ++count) {
- char tmp[12]={0};
- strncpy(tmp, &str[i], 10);
- cout << tmp ;
- if (0 == (count%10))
- cout << endl;
- else
- cout <<" ";
- }
- return 0;
- }
コンパイル方法と、実行方法
$ gcc -lgmpxx pi.cpp -o pi
$ time ./pi
計算時間の目安としては
ぐらいになります。
なお出力は、以下のURLで公開されている100万桁の円周率πのデータの形式に合わせています。
解説
- 計算精度の指定
int prec = (N+5)*log2(10); mpf_set_default_prec(prec);
gmpのデフォルトの計算精度を、(N+5)桁に設定しています。
log2(10^(N+5)) → (N+5)*log2(10) ということです。
なお、今回はN=100万なので、 precは約332万になります。つまり、GMPの変数は、一変数につき 400Kbyte 程度のメモリを消費することになります。
gmpのc++インタフェースを利用します。ヘッダファイルは gmpxx.h です。
#include <gmpxx.h>
c++インタフェースを使うと、たとえば、gmpのcインタフェースで書いた以下のコードは
- mpf_t a, b, c;
- mpf_init(a);
- mpf_init(b);
- mpf_init(c);
- mpf_set_str(a, "1234", 10);
- mpf_set_str(b, "5678", 10);
- mpf_add(c, a, b);
- mpf_out_str(stdout, 10, 10, c);
c++インタフェースでは
- mpf_class a,b,c;
- a="1234";
- b="5678";
- c=a+b;
- cout << c;
と簡潔に記述できます。
さらに
mpf_class a("1234"),b("5678"),c; c=a+b; cout << c;
とも書け、さらに圧縮して
cout << mpf_class("1234")+mpf_class("5678");
と書くことも出来ます。
おすすめ度の平均: 




ニューメリカルレシピ・イン・シー 日本語版―C言語による数値計算のレシピ
posted with amazlet at 09.03.08