C++で円周率を計算する方法について

AI実装検定のご案内

C++で円周率を扱う方法には、大きく分けて「標準ライブラリなどを使って円周率の値を取得する方法」と、「数式やアルゴリズムを使って円周率を近似計算する方法」があります。

単にプログラム内で円周率を使いたいだけなら、標準ライブラリの定数や数学関数を使うのが簡単です。

一方で、円周率がどのように計算できるのかを学びたい場合は、級数、数値積分、モンテカルロ法、Machinの公式などを使って自分で近似計算する方法が適しています。

ただし、C++で円周率を計算する際には、数値型の精度にも注意が必要です。

特に double 型では扱える有効桁数に限界があるため、どれだけ優れた公式を使っても、通常は15〜17桁程度の精度に制限されます。

より多くの桁を正確に求めたい場合は、多倍長数値型を利用する必要があります。

目次

円周率を使うだけなら標準ライブラリが便利

C++20以降なら標準の円周率定数を使える

C++20以降では、標準ライブラリに円周率の定数が用意されています。

そのため、円周率を自分で計算する必要がない場合は、標準ライブラリの定数を使うのがもっとも簡単で安全です。

この方法は、厳密には「円周率を計算する方法」ではありません。

あらかじめ用意された円周率の値を利用する方法です。

実務で円の面積、円周、三角関数、物理計算、グラフィックス処理などに円周率を使いたい場合は、自分で近似計算するよりも、標準ライブラリの定数を使うほうが適しています。

C++20以前では数学関数から求める方法もある

C++20以前の環境では、標準の円周率定数が使えない場合があります。

その場合、数学関数を使って円周率を得る方法があります。

代表的なのが、逆余弦関数を使う方法です。

数学的に、逆余弦関数で -1 を指定すると円周率 π に対応します。

そのため、C++でも数学関数を使って円周率に近い値を得ることができます。

ただし、この方法も「自分で円周率を計算している」というよりは、数学ライブラリの関数を利用して円周率の近似値を取得している方法です。

自分で定数を定義する方法もある

標準ライブラリが使えない場合は、円周率を定数として自分で定義することもできます。

ただし、定数に多くの桁を書いたとしても、double 型に入れた時点で保持できる精度には限界があります。

たとえば小数点以下50桁の円周率を書いても、double 型ではそのすべての桁を正確に保持できるわけではありません。

そのため、通常の計算であれば、double の範囲で十分な桁数だけを使えば問題ありません。

円周率を自力で計算する代表的な方法

ライプニッツ級数で計算する方法

円周率を自分で計算する方法として、もっとも理解しやすいものの一つがライプニッツ級数です。

ライプニッツ級数では、分母が奇数の分数を、プラスとマイナスを交互に繰り返しながら足していきます。

その合計に4を掛けると、円周率に近づいていきます。

この方法の大きなメリットは、考え方が非常にシンプルなことです。

初心者が「円周率は級数によって近似できる」という考え方を学ぶには、とてもよい題材です。

一方で、ライプニッツ級数は収束が非常に遅いという欠点があります。

かなり多くの項を計算しても、なかなか正確な円周率には近づきません。

たとえば100万項程度を計算しても、小数第5〜6位あたりまでしか安定しないことがあります。

そのため、ライプニッツ級数は学習用としては優れていますが、実用的な高精度計算には向いていません。

Nilakantha級数で計算する方法

Nilakantha級数も、円周率を近似するための級数の一つです。

この方法では、3を基準にして、特定の分数をプラス、マイナス、プラス、マイナスと交互に加減していきます。

ライプニッツ級数よりも比較的速く円周率に近づくため、単純な級数の中では扱いやすい方法です。

Nilakantha級数は、ライプニッツ級数よりも効率よく近似できるため、初学者が次のステップとして学ぶのに向いています。

ただし、これも本格的な高精度計算に向いている方法ではありません。

ある程度の近似値を求める学習用の方法と考えるとよいでしょう。

Machinの公式で計算する方法

より効率よく円周率を計算したい場合は、Machinの公式がよく使われます。

Machinの公式は、逆正接関数を組み合わせて円周率を求める公式です。

特に、小さい値に対する逆正接関数を使うため、級数展開したときに収束が速いという特徴があります。

ライプニッツ級数では大量の項が必要になるのに対し、Machinの公式では比較的少ない項数でも高い精度に到達できます。

そのため、「自分で円周率を計算する」というテーマでは、学習用としても実用的な近似計算としてもバランスのよい方法です。

ただし、標準ライブラリの逆正接関数をそのまま使う場合は、内部的には数学ライブラリに依存することになります。

より自力計算に近づけたい場合は、逆正接関数そのものを級数展開で計算します。

逆正接関数の級数展開を使う方法

Machinの公式を本格的に自前で実装する場合は、逆正接関数を級数展開で計算します。

逆正接関数は、一定の条件のもとで、項を交互に足し引きする級数として表せます。

Machinの公式では、逆正接関数に入る値が小さいため、級数が速く収束します。

この方法を使うと、標準ライブラリの三角関数に頼らず、数式に基づいて円周率を計算できます。

C++で円周率計算の仕組みを学びたい場合は、ライプニッツ級数よりも、Machinの公式と逆正接関数の級数展開を組み合わせた方法のほうが実用的です。

乱数や数値計算を使って円周率を求める方法

モンテカルロ法で計算する方法

モンテカルロ法は、乱数を使って円周率を近似する方法です。

考え方は、正方形の中に円を描き、その中にランダムな点を大量に打つというものです。

点が円の内側に入った割合を調べることで、円の面積と正方形の面積の比から円周率を近似できます。

この方法は、確率やシミュレーションの考え方を学ぶには非常にわかりやすいです。

乱数を使った数値実験の題材としてもよく使われます。

ただし、モンテカルロ法は円周率を高精度に求める方法としては効率がよくありません。

試行回数を大きく増やしても、精度の改善は比較的ゆっくりです。

一般的に、試行回数を100倍にしても、誤差はおおよそ10分の1程度にしかなりません。

そのため、モンテカルロ法は高精度な円周率計算には不向きです。

あくまで、乱数シミュレーションや確率的な近似計算を学ぶための方法と考えるのがよいでしょう。

数値積分で計算する方法

円周率は、積分を使って求めることもできます。

代表的な方法として、逆正接関数に関係する関数を0から1まで積分する方法があります。

この積分の値は円周率になります。

C++でこの方法を実装する場合は、台形公式やシンプソン法といった数値積分の手法を使います。

台形公式では、積分区間を細かく分割し、それぞれの小さな区間を台形として近似します。

分割数を増やすほど、一般的には精度が上がります。

シンプソン法では、台形ではなく放物線を使って近似するため、台形公式よりも少ない分割数で高い精度が出やすいです。

数値積分による円周率計算は、数値解析の学習に向いています。

ただし、円周率そのものを高精度に求める目的では、Machinの公式やChudnovskyの公式などのほうが効率的です。

高精度に円周率を計算する方法

double型には精度の限界がある

C++で円周率を計算するときに重要なのが、数値型の精度です。

多くのサンプルコードでは double 型が使われます。

double 型は一般的な数値計算では便利ですが、保持できる有効桁数には限界があります。

通常、double 型で正確に扱えるのは10進数でおおよそ15〜17桁程度です。

そのため、プログラムで小数点以下50桁や100桁を表示しても、そのすべてが数学的に正しい円周率の桁であるとは限りません。

表示桁数を増やすことと、計算精度が上がることは別です。

たとえば、出力時に多くの桁を表示しても、内部で保持している値が double であれば、実際の精度は double の範囲に制限されます。

表示桁数と計算精度は別物

C++では、出力時に表示桁数を指定できます。

しかし、これはあくまで「どれだけ表示するか」を指定しているだけです。

表示桁数を多くすれば、見た目上はたくさんの桁が表示されます。

しかし、内部の数値がその桁数まで正確でなければ、後ろの桁は信頼できません。

円周率の高精度計算を説明する場合は、「多くの桁を表示すること」と「多くの桁を正確に計算すること」を明確に分ける必要があります。

Boost.Multiprecisionを使う方法

double よりも高い精度で円周率を計算したい場合は、多倍長数値型を使う必要があります。

C++では、Boost.Multiprecisionを使うことで、通常の double よりも多くの桁を扱えます。

たとえば、50桁程度の10進精度を持つ型を使えば、より多くの桁の円周率を計算できます。

ただし、多倍長数値型を使えば自動的にすべての桁が正確になるわけではありません。

計算に使う公式の収束誤差、項数、内部精度、丸め誤差なども影響します。

つまり、高精度な円周率を求めるには、次の2つが必要です。

高精度計算に必要な要素

1つ目は、収束の速い公式を使うことです。

ライプニッツ級数のように収束が遅い公式では、多倍長型を使っても大量の項数が必要になります。

2つ目は、多倍長数値型を使うことです。

Machinの公式やChudnovskyの公式のように収束が速い公式を使っても、double 型で計算している限り、得られる精度は double の範囲に制限されます。

高精度計算では、アルゴリズムと数値型の両方が重要です。

Chudnovskyの公式による超高精度計算

Chudnovskyの公式とは

円周率の高精度計算で非常に有名なのが、Chudnovskyの公式です。

Chudnovskyの公式は収束が非常に速く、1項追加するごとにおおよそ14桁前後の精度が得られることで知られています。

そのため、円周率を大量の桁数まで計算する用途で使われることがあります。

Machinの公式よりもさらに高精度計算に向いており、円周率計算の上級的なテーマとしてよく取り上げられます。

実装には多倍長計算が必要

Chudnovskyの公式をC++で実装するには、多倍長整数や多倍長浮動小数点数が必要になります。

また、単純に階乗を毎回計算する方法では、桁数が大きくなるにつれて効率が悪くなります。

実用的な超高精度計算では、二分分割法などの高速化手法が使われることが多いです。

そのため、Chudnovskyの公式は非常に強力ですが、初心者向けというよりは中級者から上級者向けの方法です。

円周率計算を段階的に学ぶなら、最初からChudnovskyの公式に挑戦するよりも、ライプニッツ級数、Nilakantha級数、Machinの公式を理解してから進むほうがよいでしょう。

各方法の特徴と使い分け

標準ライブラリの定数を使う方法

円周率を単にプログラム内で利用したい場合に向いています。

実務では、円周率をわざわざ自分で計算する必要はほとんどありません。

C++20以降であれば、標準ライブラリに用意された円周率定数を使うのがもっとも簡単です。

この方法は、円周率計算のアルゴリズムを学ぶ目的には向いていませんが、実用面では最もおすすめです。

数学関数を使う方法

逆余弦関数などを使って円周率を得る方法です。

C++20以前でも使いやすく、手軽に円周率の近似値を得られます。

ただし、数学ライブラリに依存するため、円周率を自力で計算しているというよりは、既存の数学関数を利用している方法です。

ライプニッツ級数

円周率を級数で近似する仕組みを学ぶのに向いています。

式が単純で理解しやすいため、初心者向けの題材として優れています。

ただし、収束が非常に遅いため、実用的な高精度計算には向いていません。

Nilakantha級数

ライプニッツ級数よりも少し効率よく円周率に近づく方法です。

こちらも学習用として扱いやすく、単純な級数の比較にも向いています。

ただし、本格的な高精度計算には不向きです。

Machinの公式

自力で円周率を計算する方法として、学習面と実用面のバランスがよい方法です。

逆正接関数の級数展開と組み合わせることで、比較的少ない項数で高い精度に近づけます。

高精度計算の入門としてもおすすめです。

モンテカルロ法

乱数を使って円周率を近似する方法です。

確率、乱数、シミュレーションの学習には向いていますが、円周率を正確に求める方法としては効率が悪いです。

実行するたびに結果が変わる点も特徴です。

数値積分

積分の近似によって円周率を求める方法です。

台形公式やシンプソン法など、数値解析の基本を学ぶのに適しています。

円周率計算そのものよりも、数値積分の理解を深める目的で使うとよいでしょう。

Chudnovskyの公式

超高精度な円周率計算に向いている上級者向けの方法です。

非常に収束が速い一方で、多倍長演算や効率的な実装方法の理解が必要になります。

大量の桁数を計算したい場合に使われる代表的な公式です。

初心者におすすめの学習順

まずは円周率の定数を使ってみる

最初は、標準ライブラリや数学関数を使って円周率を表示するところから始めるとよいです。

この段階では、円周率をどう計算するかよりも、C++で小数を扱う方法、表示桁数を指定する方法、標準ライブラリを使う方法に慣れることが大切です。

次にライプニッツ級数で自力計算を学ぶ

次のステップとして、ライプニッツ級数を使って円周率を近似してみるとよいです。

この方法は収束が遅いですが、式が非常にシンプルです。

項数を増やすと少しずつ円周率に近づいていく様子を確認できるため、近似計算の考え方を理解しやすくなります。

Nilakantha級数で収束の違いを確認する

ライプニッツ級数を理解したら、Nilakantha級数と比較してみるとよいです。

同じように級数で円周率を求める方法でも、公式によって収束の速さが大きく異なることがわかります。

この比較を通じて、「円周率計算では、どの公式を使うかが重要である」という感覚を身につけられます。

Machinの公式で効率のよい計算に進む

次に学ぶべきなのがMachinの公式です。

Machinの公式は、少ない項数で高い精度を得やすいため、円周率計算の学習に非常に向いています。

逆正接関数の級数展開と組み合わせれば、数学ライブラリに頼らず円周率を自力で計算する流れも理解できます。

高精度計算では多倍長型を使う

より多くの桁を求めたい場合は、double 型ではなく、多倍長数値型を使う段階に進みます。

この段階では、表示桁数だけを増やしても意味がないこと、内部の計算精度を高める必要があることを理解するのが重要です。

Boost.Multiprecisionなどを使えば、通常の double よりも高い精度で円周率を扱えるようになります。

最後にChudnovskyの公式へ進む

さらに上級のテーマとして、Chudnovskyの公式があります。

この公式は非常に収束が速く、超高精度な円周率計算に向いています。

ただし、実装には多倍長計算や効率化の工夫が必要です。

円周率計算を深く学びたい場合は、Machinの公式まで理解したあとに挑戦するとよいでしょう。

C++で円周率を計算するときの注意点

「計算」と「定数利用」を分けて考える

円周率を扱う方法には、標準ライブラリの定数を使う方法と、自分で近似計算する方法があります。

前者は実務向きで、後者は学習向きです。

記事や教材で説明する場合は、この2つを明確に分けるとわかりやすくなります。

double型では高精度に限界がある

double 型は便利ですが、無限に正確な値を扱えるわけではありません。

円周率のように無理数を扱う場合、コンピュータ内部では必ず近似値として保持されます。

double 型では、おおよそ15〜17桁程度の有効桁数が限界です。

表示桁数を増やしても精度は上がらない

出力時に多くの桁を表示しても、内部で保持している値が正確でなければ意味がありません。

高精度な円周率を求めたい場合は、表示設定ではなく、計算に使う数値型とアルゴリズムを見直す必要があります。

収束速度と実行速度は別物

円周率計算では、公式の「収束速度」が重要です。

収束速度とは、少ない項数でどれだけ正確な値に近づくかという意味です。

ただし、収束が速い公式だからといって、必ずしも実行速度が単純に速いとは限りません。

たとえばChudnovskyの公式は収束が非常に速いですが、各項の計算には大きな数や多倍長演算が必要になります。

そのため、方法を比較する際は、「収束の速さ」と「実際の計算コスト」を分けて考えることが大切です。

まとめ

C++で円周率を扱う方法は、目的によって選ぶべきものが変わります。

単に円周率を使いたいだけなら、C++20以降の標準ライブラリの定数を使うのが最も簡単です。

C++20以前では、数学関数を使って円周率に相当する値を得る方法もあります。

一方で、円周率を自分で計算する仕組みを学びたい場合は、ライプニッツ級数やNilakantha級数がわかりやすいです。

ただし、これらは収束が遅いため、高精度計算には向いていません。

より効率よく円周率を求めたい場合は、Machinの公式が適しています。

逆正接関数の級数展開と組み合わせることで、比較的少ない項数でも高い精度に近づけます。

乱数や数値解析を学びたい場合は、モンテカルロ法や数値積分もよい題材です。

ただし、円周率を正確に求める目的では、これらの方法は必ずしも効率的ではありません。

50桁以上の高精度な円周率を求めたい場合は、double 型では不十分です。

Boost.Multiprecisionなどの多倍長数値型を使い、収束の速い公式と組み合わせる必要があります。

さらに超高精度を目指すなら、Chudnovskyの公式が有力です。

ただし、実装には多倍長演算や効率化の工夫が必要になるため、上級者向けの方法といえます。

C++で円周率計算を学ぶなら、まずは標準ライブラリで円周率を扱い、次にライプニッツ級数やNilakantha級数で近似の仕組みを理解し、その後Machinの公式や多倍長計算へ進む流れがおすすめです。

以上、C++で円周率を計算する方法についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次