今まで、円周率を Arctan 系の公式で多桁計算する概念、C++ アルゴリズムを紹介してきました。
- C++ - 円周率計算(マチンの公式)!
- C++ - 円周率計算(Klingenstierna の公式)!
- C++ - 円周率計算(オイラーの公式)!
- C++ - 円周率計算(オイラーの公式(2))!
- C++ - 円周率計算(Arctan 系公式)!
ただ、上記の過去の記事で紹介した方法は、一度級数展開したものをまとめ直した形の式にしていたため、収束の速い項も収束の遅い項と同じ計算量となっていました。
要は、計算しなくてもよい(計算しても意味のない)部分ままで計算していたことになります。
そこで、級数展開後にまとめずに公式の Arctan 毎に必要な分だけ計算する方法に変更してみました。
当然、プログラミン言語そのものが保有している三角関数は使用しません。級数展開して計算します。(多桁の円周率計算では、全く無意味ですから。但し、常用対数は影響がないので関数を使用)
0. 前提条件
- Linux Mint 14 Nadia (64bit) での作業を想定。
- g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
- 多桁計算で使用する1つの配列のサイズは8桁としている。
(当方の環境で扱える int 型の範囲は -2,147,483,648 〜 2,147,483,647 であることから) - 指定する桁数は int 型の範囲としているが、あまり大きいと計算に膨大な時間を要するので注意!
1. 今までの計算方法
(以下では、「マチンの公式」を例に説明しているが、Arctan 系の公式なら考え方はどれも同じ。)
今までは公式を以下のようなに展開してまとめた形で計算を行なっていた。
( と置き換えてもよい。)
そして、級数の計算する項数は、収束速度の遅い方に合わせて、
としていた。
2. 今回の計算方法
前述のように展開後の級数をまとめず、以下のように考える。
(ちなみに、 と置き換えてもよい。)
そして、級数の計算する工数は、第1項、第2項それぞれを以下のように考える。
ちなみに、Arctan の分子が 1 でない「オイラーの公式」の場合は、以下のようになる。
3. C++ ソース作成
例として、以下のようにソースを作成した。
- Arctan 系公式8種類から選択できるようにしている。
- 計算する桁数も入力できるようにしている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
4. C++ ソースコンパイル
1
|
|
何も出力されなければ成功。
5. 実行
以下では、「マチンの公式」を使用して小数点以下 10,000 桁を計算している。
1 2 3 4 5 6 7 8 9 10 11 |
|
公式別にテキストファイルができているはずである。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
全ての公式による計算結果が一致することを確認する。
6. 検証
今回のプログラムで利用可能にしている8つの公式を使用して、どれがどの程度高速に計算できているのかを検証してみた。
小数点以下 1,000 桁、 10,000 桁、 100,000 桁を5回計算して平均をとってみた。
ちなみに計算に使用したマシンのスペックは以下のとおり。
- CPU: Core2Duo E8500 (3.16GHz)
- メモリ: 3.9 GiB
やはり、今まで使用していたアルゴリズムと比較して高速化できている。
今までの 65% から 80% の時間で計算できるようになった。
7. 参考サイト
当方が最初に参考した C 言語によるアルゴリズムについての書籍では、Arctan をテイラー展開(グレゴリー展開)後にさらにまとめていた。
なので、当初はそれを真似たアルゴリズムにしていたが、単純に考えれば良かった、という結果でした。
ちなみに、結果が何万桁以上になる場合は、多桁(多倍長)乗算に上記の方法ではなく「Karatsuba法」や「Toom-Cook法」や「FFT(高速フーリエ変換)」を使うのが一般的なようです。
これも踏まえて、まだまだ高速化が可能であろうということは認識できている次第です。
以上。