数値演算法

(9) 数値積分法 -1-

積分法の歴史は古く、古代ギリシャの有名な数学者「アルキメデス ( Archimedes )」は、「取り尽くし法 ( Method of Exhaustion )」と呼ばれる方法を使って円や放物線などの面積を計算したことで知られています。その後、微分積分学は、「アイザック・ニュートン ( Isaac Newton )」と「ゴットフリート・ライプニッツ ( Gottfried Wilhelm Leibniz )」によって 17 世紀のヨーロッパで確立されました。今では、高校で多項式や三角関数・指数関数の原始関数を習い、それを利用すれば放物線の面積なども正確に求めることができます。
しかし、原始関数を求めることができる関数は限られていて、常に式の形が得られるわけではないので、定積分の計算には数値積分法がよく利用されます。今回は、数値積分法の手法について紹介したいと思います。

(注) 数式などの記法について (ドキュメントの中で使用している数式の表現方法に関する注意点です)

1) 区分求積法 ( Quadrature by Parts )

高校での微分・積分の授業では、最初に微分、次に積分を教えるのが通常のようで、自分も先に微分法を習いました。積分法では、「微分すると f(x) となる関数を f(x) の原始関数 ( Primitive Functions )という」という内容から始まって不定積分を覚え、次に定積分によって面積や体積を求める手法の説明がありました。今でもこの流れに変化はないと思いますが、このような教え方はあまり好評ではないそうで、実際には積分法の方が歴史的に古く、その考え方も最初は素朴なものでした。

図 1-1. 区分求積法
区分求積法

上図のような曲線 y = f(x) に対して、区間 [ a, b ] における x 軸に挟まれた部分の面積 S を求めたい時、正確にその値を求めるには、

S = ∫{a→b} f(x) dx = [ F(x) ]{a→b}

のように定積分から得ることができます。しかし、そのためには f(x) の原始関数 F(x) を求める必要があり、それは常に得られるとは限りません。古代の数学者は、原始関数を求めるのではなく、面積を求める範囲を矩形によって細かく分割し、その面積の和を求めることによって近似値として得ることを考えました。左側から k 番目の矩形の高さを、その区間内から x 座標の代表値 xk を適当に選んで f(xk) としたとき、S の近似値 S' は

S' = Σk{1→n}( f(xk) Δxk )

( 但し、Δxk は左側から k 番目の矩形の幅 )

と表すことができます。分割する数を多くすればそれだけ得られる値の精度は向上し、n → ∞ ( Δxk → 0 ) とすれば、S' → S となるので、

S=lim{n→∞} Σk{1→n}( f(xk) Δxk )
=∫{a→b} f(x) dx

これが定積分の定義になります ( 補足 1 )。

矩形の高さは「適当に選ぶ」としましたが、実際にはランダムに選ぶことはなく、何らかの規則に従って決まった位置を選択することになります。例えば、S を n 等分する場合、S は Y 軸に平行な n - 1 本の直線によって分割されるので、それらの x 座標を { xk } ( k = 1, 2, ... n - 1 ) として a = x0, b = xn とすれば、f(x0) 〜 f(xn-1) を選んだとき各矩形の左側、f(x1) 〜 f(xn) を選べば各矩形の右側を選択したことになります。また、矩形の幅 ( 分割時の区間の長さ ) も任意ではなく、等間隔に分割するのが一般的なやり方です。その場合、各矩形の幅は Δx = ( b - a ) / n と表すことができます。

関数 f(x) が単調に増加または減少しているなら、矩形の端で高さを決めるよりも中央で高さを決めた方が精度がよくなります。分割位置の間のちょうど中央での値 f( [ (xk) + f(xk-1) ] / 2 ) を各矩形の高さとして面積の総和を求める方法を「中点則 ( または中点公式 ; Midpoint Rule )」といいます。

また、両端の値の平均値 [ f(xk) + f(xk-1) ] / 2 ( k = 1, 2, ... n ) を矩形の高さとした場合、これに Δx を掛けたものは、上底と下底が f(xk), f(xk-1)、高さが Δx の台形の面積を表すことになります。この台形の面積の総和から近似値を求める方法は「台形則 ( または台形公式 ; Trapezoidal Rule )」といいます。台形則を展開すると、

S'=Σk{1→n}( Δx{ f(xk) + f(xk-1) } / 2 )
=Δx[ ( f(x1) + f(x0) ) / 2 + ( f(x2) + f(x1) ) / 2 + ... + ( f(xn) + f(xn-1) ) / 2 ]
=Δx[ f(x0) + 2f(x1) + 2f(x2) + ... + 2f(xn-1) + f(xn) ] / 2
=Δx[ f(x0) / 2 + Σk{1→n-1}( f(xk) ) + f(xn) / 2 ]

のように、非常にシンプルな式になります。

中点則と台形則を使って定積分の値を求めるサンプル・プログラムを以下に示します。

/**
   Integ_Midpoint : 中点則 ( Midpoint Rule ) による定積分計算用クラス

   関数 Integral へ引数として渡して利用する。

   例) Integral( Integ_Midpoint(), f, 0.0, 1.0, 10000 );
**/
struct Integ_Midpoint
{
  // 積分値の初期値設定
  //
  // f : 積分する関数
  // a, b : 積分する範囲
  // h : 矩形の幅
  template< class T, class F >
  T initValue( F f, T a, T b, T h )
  { return( f( a + h / 2 ) ); }

  // x の初期値設定
  //
  // a : 積分範囲の開始位置
  // h : 矩形の幅
  template< class T >
  T initX( T a, T h )
  { return( a + 3 * h / 2 ); }

  // 加算していく積分値の計算
  //
  // f : 積分する関数
  // x : f(x) を計算する x の値
  // h : 矩形の幅
  template< class T, class F >
  T operator()( F f, T x, T h )
  { return( f( x ) ); }

  // 和を計算した後の補正
  //
  // val : 補正前の積分値
  // h : 矩形の幅
  template< class T >
  T cleanUp( T val, T h )
  { return( val * h ); }
};

/**
   Integ_Trapezoidal : 台形則 ( Trapezoidal Rule ) による定積分計算用クラス

   関数 Integral へ引数として渡して利用する。

   例) Integral( Integ_Trapezoidal(), f, 0.0, 1.0, 10000 );
**/
struct Integ_Trapezoidal
{
  // 積分値の初期値設定
  //
  // f : 積分する関数
  // a, b : 積分する範囲
  // h : 矩形の幅
  template< class T, class F >
  T initValue( F f, T a, T b, T h )
  { return( ( f( a ) + f( b ) ) / 2 ); }

  // x の初期値設定
  //
  // a : 積分範囲の開始位置
  // h : 矩形の幅
  template< class T >
  T initX( T a, T h )
  { return( a + h ); }

  // 加算していく積分値の計算
  //
  // f : 積分する関数
  // x : f(x) を計算する x の値
  // h : 矩形の幅
  template< class T, class F >
  T operator()( F f, T x, T h )
  { return( f( x ) ); }

  // 和を計算した後の補正
  //
  // val : 補正前の積分値
  // h : 矩形の幅
  template< class T >
  T cleanUp( T val, T h )
  { return( val * h ); }
};

/*
  Integral : 区分求積法による積分値の計算

  計算手法 ( 中点則・台形則など ) は引数 op にて指定する。
  積分範囲の大小関係が逆転している ( a > b の ) 場合、積分値の符号が逆転することに注意。

  op : 積分値を計算する手法
  f : 積分値を計算する対象の関数
  a,b : 積分範囲
  n : 分割数 ( 大きいほど精度が上がるが、処理時間は長くなる )
*/
template< class T, class F, class Op >
  T Integral( Op op, F f, T a, T b, unsigned int n )
{
  assert( n > 0 );
  bool invSign; // 符号反転するか

  // a > b なら swap して後で符号を反転する
  if ( a > b ) {
    std::swap( a, b );
    invSign = true;
  } else {
    invSign = false;
  }

  T h( ( b - a ) / n ); // 矩形の幅

  // 計算開始

  T ans = op.initValue( f, a, b, h ); // 積分値の初期状態
  T x = op.initX( a, h );       // x の初期値
  for ( unsigned int i = 1 ; i < n ; ++i ) {
    ans += op( f, x, h ); // f(x) を求めて加算する
    x += h;
  }

  // 符号反転
  if ( invSign ) ans *= -1;

  // 正しい積分値にする
  return( op.cleanUp( ans, h ) );
}

計算処理は非常に単純で、関数 f(x) の値を求めながら変数 ans に総和を求めているだけです。その処理を行うのが関数 Integral です。前処理として、分割数がゼロだった場合は処理を中断するようにし ( assert を使っているためプログラム自体が停止します。その他に例外を投げたり、NaN などの無効値を返すやり方もあります )、また a > b である場合は変数を入れ替えると同時に、後で総和の符号を反転する処理を行えるように変数 invSign のフラグを立てています。これは、

∫{a→b} f(x) dx = - ∫{b→a} f(x) dx

という定義によるものです。ところで、関数 f(x) の値は負値にもなり得るので、矩形の面積も負になる可能性があります。これも定積分の定義により、x 軸よりも下側の面積は負値として扱うため、符号は変えずにそのまま総和を計算します。

処理の方式は引数 op で切り替えられるようにしています。その引数として渡すのが中点則の Integ_Midpoint クラスと台形則の Integ_Trapezoidal クラスです。これらのクラスは 4 つのメンバ関数 initValue, initX, operator(), cleanUp を共通で持っています。initValue は積分値の初期値を計算するためのもので、最初の矩形の面積はこの関数で計算します。次に x 座標を初期化しますが、これは二番目の矩形に対する x 座標を計算することになるのに注意してください。ループ処理では、二番目の矩形から面積を算出します。このとき使うのが operator() です。最後の cleanUp は求めた和に定数等を作用させるために利用します。和の計算時に共通となる部分は、最後の cleanUp 時に乗除させた方が精度が向上します。


いくつかの関数を使い、実際に計算を行った結果を以下に示します。計算した定積分の式は次の通りです。

∫{0→1} 3x2 dx

∫{0→1} 4( 1 - x2 )1/2 dx

上側の式の値は 1 になり、下側の ( 1 - x2 )1/2 は半径 1 の円の第一象限における方程式を表しているので、定積分の値は π になります。

表 1-1. ∫{0→1} 3x2 dx の計算結果
n中点則台形則
計算結果誤差計算結果誤差
10.75000000000-0.250000000001.500000000000.50000000000
100.99750000000-0.002500000001.005000000000.00500000000
1000.99997500000-0.000025000001.000050000000.00005000000
10000.99999975000-0.000000250001.000000500000.00000050000
100000.99999999750-0.000000002501.000000005000.00000000500
1000000.99999999997-0.000000000031.000000000050.00000000005
 
表 1-1. ∫{0→1} 4 sqrt( 1 - x2 ) dx の計算結果
中点則台形則
n計算結果誤差計算結果誤差
13.464101615140.322508961552.00000000000-1.14159265359
103.152411433260.010818779673.10451832625-0.03707432734
1003.141936857900.000344204313.14041703178-0.00117562181
10003.141603544910.000010891323.14155546691-0.00003718668
100003.141592998020.000000344443.14159147761-0.00000117598
1000003.141592664490.000000010903.14159261641-0.00000003718

結果を見ると、少なくとも 1000 等分、できれば 10000 等分に分割しなければ充分な精度は得られないことが分かります。関数が複雑になればそれだけ処理時間も長くなるため、総和を求める時の分割数を少なくしても充分な精度が得られるような方法が必要となります。


2) シンプソン則 ( Simpson's Rule )

台形則では、区間内の定積分値を台形の面積として近似計算したわけですが、これは、区間内の関数 f(x) を直線で近似したことと同じ意味になります。

ak = ( f(xk) + f(xk-1) ) / Δx

y = ak( x - xk ) + f(xk) = ak x + bk

とすれば、各区間での関数 y = f(x) を直線 y = ak x + bk に置き換えたことになり、以前紹介した「画像のサンプル補間」における「線形補間法」と同様な手法を利用しています。サンプル補間では直線近似をしてピクセル間の値を決めていたのに対して、ここでは面積を求めるために関数を直線で置き換えていることになります。

図 2-1. 台形則が面積として計算する部分
台形則

画像のサンプル補間」の中で紹介した「多項式補間」では、ピクセル間の値を多項式を使って補間しています。定積分においても任意の関数を多項式で近似すれば、多項式の定積分は簡単にできるので、より正確な近似計算が少ない分割数で実現できそうです。

図 2-2. 多項式による関数の近似
シンプソン則

まずは、二次式による近似を検討してみます。二次式 P(x) = ax2 + bx + c の各未知数 a, b, c を求めるためには三点を決めればよいので、両端の座標 ( xk-1, f(xk-1) ), ( xk, f(xk) ) とその中点の座標 ( xm, f(xm) ) ( 但し、xm = ( xk-1 + xk ) / 2 ) を使って連立方程式を解きます。

( xk-1, f(xk-1) ) = ( xL, yL )

( xm, f(xm) ) = ( xM, yM )

( xk, f(xk) ) = ( xR, yR )

として、解きやすくするために P(x) = a( x - xM )2 + b( x - xM ) + c と表すと、連立方程式は

( xL - xM )2a + ( xL - xM )b + c = yL

c = yM

( xR - xM )2a + ( xR - xM )b + c = yR

となります。ところが、

xR - xM = xM - xL = ( xR - xL ) / 2

なので、xR - xL = h とおくと、

( h2 / 4 )a - ( h / 2 )b + yM = yL

( h2 / 4 )a + ( h / 2 )b + yM = yR

と、非常に簡単になります。この連立方程式を解くと、

a = 2( yL - 2yM + yR ) / h2

b = ( yR - yL ) / h

c = yM

P(x) の積分値を求めると、

∫{xL→xR} P(x) dx=[ (1/3)a( x - xM )3 + (1/2)b( x - xM )2 + cx ]{xL→xR}
=(1/3)a{ ( xR - xM )3 - ( xL - xM )3 } + (1/2)b{ ( xR - xM )2 - ( xL - xM )2 } + c{ ( xR - xM ) - ( xL - xM ) }
=ah3 / 12 + ch
=h( yL - 2yM + yR ) / 6 + hyM
=h( yL + 4yM + yR ) / 6

よって、

∫{xL→xR} f(x) dx ≅ h( yL + 4yM + yR ) / 6

という近似式ができます。これを「シンプソン則 ( Simpson's Rule )」といいます。積分する区間を偶数個に分割し、( x2k, f(x2k) ) から ( x2k+2, f(x2k+2) ) までの区間にシンプソン則を適用すると、各区間の幅を h としたとき

∫{x2k→x2k+2} f(x) dx ≅ h( f(x2k) + 4f(x2k+1) + f(x2k+2) ) / 3

なので、x0 から x2n までの和を取れば

∫{x0→x2n} f(x) dx( h / 3 )[ { f(x0) + 4f(x1) + f(x2) } + { f(x2) + 4f(x3) + f(x4) } + ... + { f(x2n-2) + 4f(x2n-1) + f(x2n) } ]
=( h / 3 ){ f(x0) + 4Σk{1→n}( f(x2k-1) ) + 2Σk{1→n-1}( f(x2k) ) + f(x2n) }

となり、分割数を多くすればそれだけ精度を上げることもできます。これを「合成シンプソン則 ( Composite Simpson's Rule )」といいます。

図 2-3. シンプソン則による区間分割
合成シンプソン則での分割単位

シンプソン則を使って定積分の値を求めるサンプル・プログラムを以下に示します。

/**
   Integ_Simpson : シンプソン則 ( Composite Simpson's Rule ) による定積分計算用クラス

   関数 Integral へ引数として渡して利用する。

   例) Integral( Integ_Simpson(), f, 0.0, 1.0, 10000 );
**/
struct Integ_Simpson
{
  // 積分値の初期値設定
  //
  // f : 積分する関数
  // a, b : 積分する範囲
  // h : 矩形の幅
  template< class T, class F >
  T initValue( F f, T a, T b, T h )
  { return( f( a ) + 4 * f( b - h / 2 ) + f( b ) ); }

  // x の初期値設定
  //
  // a : 積分範囲の開始位置
  // h : 矩形の幅
  template< class T >
  T initX( T a, T h )
  { return( a ); }

  // 加算していく積分値の計算
  //
  // f : 積分する関数
  // x : f(x) を計算する x の値
  // h : 矩形の幅
  template< class T, class F >
  T operator()( F f, T x, T h )
  { return( 4 * f( x + h / 2 ) + 2 * f( x + h ) ); }

  // 和を計算した後の補正
  //
  // val : 補正前の積分値
  // h : 矩形の幅
  template< class T >
  T cleanUp( T val, T h )
  { return( val * h / 6 ); }
};

中点則、台形則を含めて、以下の定積分値を求めた結果は次のようになります。

∫{0→1} 4( 1 - x2 )1/2 dx

∫{0→π/2} cos θ dθ

上側は中点則・台形則のテストで利用したものと同じ式です。下側の定積分値は 1 になります。

表 2-1. ∫{0→1} 4( 1 - x2 )1/2 dx の計算結果
nSimpson則中点則台形則
計算結果誤差計算結果誤差計算結果誤差
12.97606774343-0.165524910163.464101615140.322508961552.00000000000-1.14159265359
103.13644706426-0.005145589333.152411433260.010818779673.10451832625-0.03707432734
1003.14143024919-0.000162404403.141936857900.000344204313.14041703178-0.00117562181
10003.14158751891-0.000005134683.141603544910.000010891323.14155546691-0.00003718668
100003.14159249122-0.000000162373.141592998020.000000344443.14159147761-0.00000117598
1000003.14159264846-0.000000005133.141592664490.000000010903.14159261641-0.00000003718
 
表 2-1. ∫{0→π/2} cos θ dθ の計算結果
nSimpson則中点則台形則
計算結果誤差計算結果誤差計算結果誤差
11.002279877490.002279877491.110720734540.110720734540.78539816340-0.21460183660
101.000000211550.000000211551.001028824140.001028824140.99794298635-0.00205701365
1001.000000000020.000000000021.000010280910.000010280910.99997943824-0.00002056176
10001.000000000000.000000000001.000000102810.000000102810.99999979438-0.00000020562
100001.00000000000-0.000000000001.000000001030.000000001030.99999999794-0.00000000206
1000001.00000000000-0.000000000001.000000000010.000000000010.99999999998-0.00000000002

cos θ の積分は 100 等分程度でかなりの精度まで一致していることが分かります。π の値を求める上側の式においても、中点則や台形則に比べると精度が向上しているように見えますが、cos θ の場合と比較すると劇的な変化とはいえないようです。この件については次の章でもう少し詳しく調べてみたいと思います。


3) ニュートン・コーツの公式 ( Newton-Cotes Formulas )

台形則は一次式、シンプソン則は二次式で関数を近似することによって定積分値を求めていました。よって、より高次の多項式で近似をすれば、精度を向上させることが期待できそうです。しかし、高次になるほど未知数となる係数の数は多くなるため、連立方程式の計算に手間がかかるようになります。そこで、「多項式補間」で利用した「ラグランジュの多項式 ( Lagrange Polynomial )」を使います。

関数 f(x) 上の任意の点を ( xi, f( xi ) ) としたとき、

LN(x) = Σi{0→N}( f(xi) li(x) )

但し、

li( x )=Πj{0→N,j≠i}( ( x - xj ) / ( xi - xj ) )
=( x - x0 )( x - x1 )...( x - xi-1 )( x - xi+1 )...( x - xN ) / ( xi - x0 )( xi - x1 )...( xi - xi-1 )( xi - xi+1 )...( xi - xN )

とすれば、

li( xj )=1 ( i = j )
=0 ( i ≠ j )

となるので f( xi ) = LN( xi ) を満たします。そこで、f(x) の定積分値を LN(x) で近似して、

∫{a→b} f(x) dx∫{a→b} LN(x) dx
=∫{a→b} Σi{0→N}( f( xi ) li( x ) ) dx
=Σi{0→N}( f( xi )∫{a→b} li( x ) dx )

∫{a→b} li( x ) dx = wi、f( xi ) = fi として、

∫{a→b} f(x) dx ≅ Σi{0→N}( wi fi )

これを「ニュートン・コーツの公式 ( Newton-Cotes Formulas )」といいます。N = 1 であれば台形則、N = 2 であればシンプソン則を表し、ニュートン・コーツの公式はそれらを一般化したものと考えることができます。N = 3 の場合、三等分したときの各区間を h とすれば

l0( x )=( x - x1 )( x - x2 )( x - x3 ) / ( x0 - x1 )( x0 - x2 )( x0 - x3 )
=-( x - x1 )( x - x2 )( x - x3 ) / 6h3
l1( x )=( x - x0 )( x - x2 )( x - x3 ) / 2h3
l2( x )=-( x - x0 )( x - x1 )( x - x3 ) / 2h3
l3( x )=( x - x0 )( x - x1 )( x - x2 ) / 6h3

ここで l0( x ) に対して x - x2 = X とおくと、

l0( x )=-( X + x2 - x1 )X( X + x2 - x3 ) / 6h3
=-X( X + h )( X - h ) / 6h3
=-X3 / 6h3 + X / 6h

なので

w0=∫{x0→x3} l0( x ) dx = ∫{x0 - x2 → x3 - x2} l0( x ) dX
=[ - X4 / 24h3 + X2 / 12h ]{-2h→h}
=( -h / 24 + h / 12 ) - ( -2h / 3 + h / 3 ) = 3h / 8

になります。また、l1( x ) に対して x - x2 = X とおくと、

l1( x )=( X + x2 - x0 )X( X + x2 - x3 ) / 2h3
=X( X + 2h )( X - h ) / 2h3
=X3 / 2h3 + X2 / 2h2 - X / h

となって、

w1=∫{x0→x3} l1( x ) dx = ∫{x0 - x2 → x3 - x2} l1( x ) dX
=[ X4 / 8h3 + X3 / 6h2 - X2 / 2h ]{-2h→h}
=( h / 8 + h / 6 - h / 2 ) - ( 2h - 4h / 3 - 2h ) = 9h / 8

と求めることができます。w2、w3 も同様な方法によってそれぞれ 9h / 8、3h / 8 と求められるので、

∫{x0→x3} f(x) dx ≅ ( 3h / 8 )( f0 + 3f1 + 3f2 + f3 )

となります。主要な公式について、その分割数と式をまとめたものを以下に示します。

表 3-1. 主要な公式の一覧
分割数公式の名前公式合成積分公式
1台形則
(Trapezoid Rule)
( h / 2 )( f0 + f1 )( h / 4 ){ f0 + 2Σk{1→n-1}( fk ) + fn }
2シンプソン則
(Simpson's Rule)
( h / 3 )( f0 + 4f1 + f2 )( h / 3 ){ f0 + 4Σk{1→n}( f2k-1 ) + 2Σk{1→n-1}( f2k ) + f2n }
3シンプソンの 3/8 則
(Simpson's 3/8 Rule)
( 3h / 8 )( f0 + 3f1 + 3f2 + f3 )( 3h / 8 ){ f0 + 3Σk{1→n}( f3k-2 + f3k-1 ) + 2Σk{1→n-1}( f3k ) + f3n }
4ブール則
(Boole's Rule)
( 2h / 45 )( 7f0 + 32f1 + 12f2 + 32f3 + 7f4 )( 2h / 45 ){ 7f0 + 32Σk{1→n}( f4k-3 + f4k-1 ) + 12Σk{1→n}( f4k-2 ) + 14Σk{1→n-1}( f4k ) + 7f4n }

シンプソンの 3/8 則とブール則によって定積分の値を求めるサンプル・プログラムを以下に示します。

/**
   Integ_Simpson38 : シンプソンの 3/8 則 ( Simpson's 3/8 Rule ) による定積分計算用クラス

   関数 Integral へ引数として渡して利用する。

   例) Integral( Integ_Simpson38(), f, 0.0, 1.0, 10000 );
**/
struct Integ_Simpson38
{
  // 積分値の初期値設定
  //
  // f : 積分する関数
  // a, b : 積分する範囲
  // h : 矩形の幅
  template< class T, class F >
  T initValue( F f, T a, T b, T h )
  { return( f( a ) + 3 * ( f( b - h / 3 ) + f( b - 2 * h / 3 ) ) + f( b ) ); }

  // x の初期値設定
  //
  // a : 積分範囲の開始位置
  // h : 矩形の幅
  template< class T >
  T initX( T a, T h )
  { return( a ); }

  // 加算していく積分値の計算
  //
  // f : 積分する関数
  // x : f(x) を計算する x の値
  // h : 矩形の幅
  template< class T, class F >
  T operator()( F f, T x, T h )
  { return( 3 * ( f( x + h / 3 ) + f( x + 2 * h / 3 ) ) + 2 * f( x + h ) ); }

  // 和を計算した後の補正
  //
  // val : 補正前の積分値
  // h : 矩形の幅
  template< class T >
  T cleanUp( T val, T h )
  { return( val * h / 8 ); }
};

/**
   Integ_Boole : ブール則 ( Boole's Rule ) による定積分計算用クラス

   関数 Integral へ引数として渡して利用する。

   例) Integral( Integ_Boole(), f, 0.0, 1.0, 10000 );
**/
struct Integ_Boole
{
  // 積分値の初期値設定
  //
  // f : 積分する関数
  // a, b : 積分する範囲
  // h : 矩形の幅
  template< class T, class F >
  T initValue( F f, T a, T b, T h )
  { return( 7 * f( a ) + 32 * ( f( b - 3 * h / 4 ) + f( b - h / 4 ) ) + 12 * f( b - h / 2 ) + 7 * f( b ) ); }

  // x の初期値設定
  //
  // a : 積分範囲の開始位置
  // h : 矩形の幅
  template< class T >
  T initX( T a, T h )
  { return( a ); }

  // 加算していく積分値の計算
  //
  // f : 積分する関数
  // x : f(x) を計算する x の値
  // h : 矩形の幅
  template< class T, class F >
  T operator()( F f, T x, T h )
  { return( 32 * ( f( x + h / 4 ) + f( x + 3 * h / 4 ) ) + 12 * f( x + h / 2 ) + 14 * f( x + h ) ); }

  // 和を計算した後の補正
  //
  // val : 補正前の積分値
  // h : 矩形の幅
  template< class T >
  T cleanUp( T val, T h )
  { return( val * h / 90 ); }
};

シンプソン則、シンプソンの 3/8 則、ブール則を使った以下の定積分値の計算結果は次のようになります。

∫{0→1} 4( 1 - x2 )1/2 dx

∫{0→π/2} cos θ dθ

上式はどちらもシンプソン則のテストで利用したものと同じ式です。

表 3-2. ∫{0→1} 4( 1 - x2 )1/2 dx の計算結果
Simpson則3/8則Boole則
n計算結果誤差計算結果誤差計算結果誤差
12.97606774343-0.165524910163.03224755112-0.109345102473.09076364905-0.05082900454
103.13644706426-0.005145589333.13818375945-0.003408894143.13999723825-0.00159541534
1003.14143024919-0.000162404403.14148502474-0.000107628853.14154224064-0.00005041295
10003.14158751891-0.000005134683.14158925061-0.000003402983.14159105951-0.00000159408
100003.14159249122-0.000000162373.14159254598-0.000000107613.14159260318-0.00000005041
1000003.14159264846-0.000000005133.14159265019-0.000000003403.14159265200-0.00000000159
 
表 3-3. ∫{0→π/2} cos θ dθ の計算結果
Simpson則3/8則Boole則
n計算結果誤差計算結果誤差計算結果誤差
11.002279877490.002279877491.001004923310.001004923310.99999156547-0.00000843453
101.000000211550.000000211551.000000094010.000000094010.99999999999-0.00000000001
1001.000000000020.000000000021.000000000010.000000000011.000000000000.00000000000
10001.000000000000.000000000001.000000000000.000000000001.000000000000.00000000000
100001.00000000000-0.000000000001.00000000000-0.000000000001.00000000000-0.00000000000
1000001.00000000000-0.000000000001.00000000000-0.000000000001.00000000000-0.00000000000

∫{0→1} 4( 1 - x2 )1/2 dx と ∫{0→π/2} cos θ dθ を台形則から Boole 則まで、分割数を 1, 10, 100 として計算したときの誤差は次のようになります。

表 3-4. ∫{0→1} 4( 1 - x2 )1/2 dx の各公式における誤差
定積分法分割数 「()内は台形則を1.00としたときの比率」
110100
台形則-1.14159265359 (1.00)-0.03707432734 (1.00)-0.00117562181 (1.00)
Simpson則-0.16552491016 (1.45E-1)-0.00514558933 (1.39E-1)-0.00016240440 (1.38E-1)
3/8則-0.10934510247 (9.58E-2)-0.00340889414 (9.19E-2)-0.00010762885 (9.16E-2)
Boole則-0.05082900454 (4.45E-2)-0.00159541534 (4.30E-2)-0.00005041295 (4.29E-2)
 
表 3-5. ∫{0→π/2} cos θ dθ の各公式における誤差
定積分法分割数 「()内は台形則を1.00としたときの比率」
110100
台形則-0.21460183660 (1.00)-0.00205701365 (1.00)-0.00002056176 (1.00)
Simpson則0.00227987749 (1.06E-1)0.00000021155 (1.03E-4)0.00000000002 (1E-6)
3/8則0.00100492331 (4.68E-3)0.00000009401 (4.57E-5)0.00000000001 (5E-7)
Boole則-0.00000843453 (3.93E-5)-0.00000000001 (5E-9)0.00000000000 (-)

cos θ の定積分は、高次の多項式を利用するほど劇的に精度が向上する反面、π を求める上側の定積分は台形則を除くと大きな精度の向上は得られていないことが分かります。注意点として、高次の多項式を利用している方法では区間内をさらに分割して f(x) の値を求めているので、f(x) を取得する回数は倍々に増えています。例えば分割数が 10 の場合、台形則は f(x) の演算を初期化時に 2 回、ループ内で 9 回の計 11 回行っているのに対し、Simpson 則は初期化で 3 回、ループ内で 18回の計 21 回、3/8 則では初期化で 4 回、ループ内で 27 回の計 31 回、最後の Boole 則では初期化で 5 回、ループ内で 36 回の計 41 回 f(x) を計算しています。それを考慮すると、上側の式に対しては次数を増やすことによる効果はほとんど見られないことになります。

( 1 - x2 )1/2 の定積分において精度が向上しない理由は、x = 1 の付近で関数の値が急激に減少し、特に x = 1 では導関数の値が発散するためなので、x = 1 付近での定積分が行われないような工夫をすることで誤差を小さくすることができます。例えば、直線 y = x によって円弧は等分されるので、円弧と直線によって囲まれた部分の面積を定積分法で求めてそれを 8 倍することで、π の近似値を求めることができます。円弧と直線との交点は ( √2 / 2, √2 / 2 ) であり、面積は ( 1 - x2 )1/2 - x の定積分によって求められるので、計算式は

∫{0→√2/2} 8[ ( 1 - x2 )1/2 - x ] dx

になります。

図 3-1. 円弧と直線で囲まれた部分の定積分
円弧と直線で囲まれた部分の定積分
 
表 3-6. ∫{0→√2/2} 8[ ( 1 - x2 )1/2 - x ] dx の計算結果
台形則Simpson則3/8則Boole則
n計算結果誤差計算結果誤差計算結果誤差計算結果誤差
12.82842712475-0.313165528843.13714412300-0.004448530593.13948828738-0.002104366213.14145643965-0.00013621394
103.13826261523-0.003330038363.14159183222-0.000000821373.14159228795-0.000000365643.14159265300-0.00000000059
1003.14155932059-0.000033333003.14159265351-0.000000000083.14159265355-0.000000000043.141592653590.00000000000
10003.14159232026-0.000000333333.14159265359-0.000000000003.14159265359-0.000000000003.14159265359-0.00000000000
100003.14159265026-0.000000003333.141592653590.000000000003.141592653590.000000000003.14159265359-0.00000000000
1000003.14159265355-0.000000000043.14159265359-0.000000000003.14159265359-0.000000000003.14159265359-0.00000000000
 
表 3-7. ∫{0→√2/2} 8[ ( 1 - x2 )1/2 - x ] dx の各公式における誤差
定積分法分割数 「()内は台形則を1.00としたときの比率」
110100
台形則-0.31316552884 (1.00)-0.00333003836 (1.00)-0.00003333300 (1.00)
Simpson則-0.00444853059 (1.42E-2)-0.00000082137 (2.47E-4)-0.00000000008 (2E-6)
3/8則-0.00210436621 (6.72E-3)-0.00000036564 (1.10E-4)-0.00000000004 (1E-6)
Boole則-0.00013621394 (4.35E-4)-0.00000000059 (1.8E-7)0.00000000000 (-)

今度は高い精度で結果が得られ、高次の多項式を利用することによる効果も見られます。下に示したのは、√2/2 から 1 までの範囲の定積分値を求め、それに三角形部分の面積を加算した場合の算出結果です。こちらは精度が悪くなることが予想され、また結果も予想通りのものとなっています。

表 3-8. ∫{√2/2→1} 8[ ( 1 - x2 )1/2 - x ] dx の計算結果
台形則Simpson則3/8則Boole則
n計算結果誤差計算結果誤差計算結果誤差計算結果誤差
12.82842712475-0.313165528843.09000340813-0.051589245463.10739734495-0.034195308643.12557412066-0.01601853293
103.13038555457-0.011207099023.13996386005-0.001628793543.14051329432-0.001079359273.14108716975-0.00050548384
1003.14122559003-0.000367063563.14154117516-0.000051478433.14155853678-0.000034116813.14157667237-0.00001598122
10003.14158092141-0.000011732183.14159102579-0.000001627803.14159157477-0.000001078823.14159214823-0.00000050536
100003.14159228134-0.000000372253.14159260211-0.000000051483.14159261947-0.000000034123.14159263761-0.00000001598
1000003.14159264181-0.000000011783.14159265197-0.000000001623.14159265252-0.000000001073.14159265309-0.00000000050
 
表 3-9. ∫{√2/2→1} 8[ ( 1 - x2 )1/2 - x ] dx の各公式における誤差
定積分法分割数 「()内は台形則を1.00としたときの比率」
110100
台形則-0.31316552884 (1.00)-0.01120709902 (1.00)-0.00036706356 (1.00)
Simpson則-0.05158924546 (1.65E-1)-0.00162879354 (1.45E-1)-0.00005147843 (1.40E-1)
3/8則-0.03419530864 (1.09E-1)-0.00107935927 (9.63E-2)-0.00003411681 (9.29E-2)
Boole則-0.01601853293 (5.12E-2)-0.00050548384 (4.51E-2)-0.00001598122 (4.35E-2)

この結果から、数値積分法では関数の性質によって専用の処理方法を用意することがある程度必要で、汎用に使える手法というのは一般的にはないということになります。

これまでは、関数を高次多項式で近似して積分値を求める手法について紹介してきましたが、次数を大きくするほど公式は複雑になるので、できるだけ高次にすればよいというわけでもなく、また Simpson 則でも工夫次第で充分な精度が得られるので、次は精度を上げるための別の手法を紹介したいと思います。その手法を説明する前に、その中で利用されている「ベルヌーイ数」を先に紹介しておきます。


4) ベルヌーイ数 ( Bernoulli Number )

1 から n までの和は「三角数 ( Triangular Number )」と呼ばれ、点を三角形の形に並べたときの点の個数になっています。この数に関して、数学者のガウスが小学生時代、先生から出された課題をあっという間に解いてしまったという逸話があります。その時の問題は「1 から 100 までの数の和を求める」という、三角数を求める問題と同じものでした。n = 4 のときの三角数は、下図の中の黒点の数になります。これを上下反転したものを右側に追加すると(白点の部分)、横に五個、縦に四個の点が並んだ平行四辺形の形になるので、三角数は 5 x 4 / 2 = 10 と計算できます。

図 4-1. 三角数 ( n = 4 の場合 )
三角数(n=4)

この考えかたを応用すると、1 から n までの和を計算するための公式が得られます。まず、1 から n までの数を横に並べ、その下に n から 1 まで数を逆に並べます。

1   2   3   4 ... n-1   n
n n-1 n-2 n-3 ...   2   1

上下の数どうしをそれぞれ足し合わせていきます。

    1   2   3   4 ... n-1   n
    n n-1 n-2 n-3 ...   2   1
+)______________________________
  n+1 n+1 n+1 n+1 ... n+1 n+1

それぞれの和は n + 1 になり、それが n 個できるので、その和は n( n + 1 ) になります。しかし、この中で 1 から n までの数が二回ずつ加算されているので、2 で割ることで求める三角数 n( n + 1 ) / 2 が得られます。

次に、n 個の数の和ではなく n 個の平方数の和を求めることを検討してみます。この和を S2(n) と表すと、

S2(n) = 12 + 22 + ... + n2 = Σk{1→n}( k2 )

になります。ここでは三角数を求める方法を利用することはできないので、別の手法を考える必要があります。そこで、次のような等式を利用します。

( n + 1 )3 = 13 + ( 23 - 13 ) + ( 33 - 23 ) + ... + { ( n + 1 )3 - n3 } = 1 + Σk{1→n}( ( k + 1 )3 - k3 )

中辺の各項は互いに打ち消しあって左辺の形になります。このような和の形は「望遠鏡和 ( Telescoping Sum )」と呼ばれ、典型的な例としては

Σk{1→n-1}( 1 / k( k + 1 ) )=Σk{1→n-1}( { 1 / k } - { 1 / ( k + 1 ) } )
=( 1 / 1 - 1 / 2 ) + ( 1 / 2 - 1 / 3 ) + ... + { 1 / ( n - 1 ) - 1 / n }
=1 - 1 / n = ( n - 1 ) / n

というものがあります。先ほどの変形は ( n + 1 )3 に対して無理矢理、望遠鏡和の形に表したと考えることができます。

( k + 1 )3 = k3 + 3k2 + 3k + 1 なので、先ほどの式を変形すると

( n + 1 )3=1 + Σk{1→n}( k3 + 3k2 + 3k + 1 - k3 )
=1 + 3Σk{1→n}( k2 ) + 3Σk{1→n}( k ) + Σk{1→n}( 1 )

ここで、Σk{1→n}( k2 ) は求める和 S2(n) になります。また、Σk{1→n}( k ) は三角数の和を表し、Σk{1→n}( 1 ) = n なので

( n + 1 )3 = 1 + 3S2(n) + 3n( n + 1 ) / 2 + n

これを S2(n) について解くと、

S2(n)={ ( n + 1 )3 - 3n( n + 1 ) / 2 - n - 1 } / 3
={ n3 + 3n2 + 3n + 1 - ( 3n2 + 3n ) / 2 - n - 1 } / 3
=( 2n3 + 3n2 + n ) / 6

これで、S2(n) を解くことができました。同様の手法を使って、一般解として

Sm(n) = 1m + 2m + ... + nm = Σk{1→n}( km )

を求めてみたいと思います。まず、( n + 1 )m+1 を望遠鏡和の形に表して

( n + 1 )m+1 = 1m+1 + ( 2m+1 - 1m+1 ) + ( 3m+1 - 2m+1 ) + ... + { ( n + 1 )m+1 - nm+1 } = 1 + Σk{1→n}( ( k + 1 )m+1 - km+1 )

二項定理」より、二項係数を C( n, r ) で表すと

( k + 1 )m+1 = ( 1 + k )m+1 = Σr{0→m+1}( C( m + 1, r ) kr )

を代入すると、

( n + 1 )m+1=1 + Σk{1→n}( Σr{0→m+1}( C( m + 1, r ) kr ) - km+1 )
=1 + Σk{1→n}( Σr{0→m}( C( m + 1, r ) kr ) )
=1 + Σr{0→m}( C( m + 1, r ) Σk{1→n}( kr ) )

Σk{1→n}( kr ) = Sr(n) なので、

( n + 1 )m+1 = 1 + Σr{0→m}( C( m + 1, r ) Sr(n) )

総和の中から r = m の部分だけを抽出してその部分について解くと

C( m + 1, m ) Sm(n) = ( n + 1 )m+1 - 1 - Σr{0→m-1}( C( m + 1, r ) Sr(n) )

C( m + 1, m ) = C( m + 1, 1 ) = m + 1 なので

Sm(n) = { ( n + 1 )m+1 - 1 } / ( m + 1 ) - { Σr{0→m-1}( C( m + 1, r ) Sr(n) ) } / ( m + 1 )

これで、Sm(n) を計算するための漸化式が得られたことになります。三角数の和は S1(n) = n( n + 1 ) / 2 でした。これを上記の漸化式で求めてみると

S1(n) = { ( n + 1 )2 - 1 } / 2 - C( 2, 0 ) S0(n) / 2

S0(n) はゼロ乗の総和を意味するので n とすれば、

S1(n) = { ( n + 1 )2 - 1 } / 2 - n / 2 = n( n + 1 ) / 2

になります。S2(n) は

S2(n)={ ( n + 1 )3 - 1 } / 3 - { C( 3, 0 ) S0(n) + C( 3, 1 ) S1(n) } / 3
={ ( n + 1 )3 - 1 } / 3 - { n + 3n( n + 1 ) / 2 } / 3
=( n3 + 3n2 + 3n ) / 3 - ( 3n2 + 5n ) / 6
=( 2n3 + 3n2 + n ) / 6

で、先ほど計算した結果と一致します。さらに、

S3(n)={ ( n + 1 )4 - 1 } / 4 - { C( 4, 0 ) S0(n) + C( 4, 1 ) S1(n) + C( 4, 2 ) S2(n) } / 4
={ ( n + 1 )4 - 1 } / 4 - { n + 4n( n + 1 ) / 2 + 6( 2n3 + 3n2 + n ) / 6 } / 4
=( n4 + 4n3 + 6n2 + 4n ) / 4 - ( 2n3 + 5n2 + 4n ) / 4
=( n4 + 2n3 + n2 ) / 4

より、三乗の総和を計算する公式も得ることができます。


Sm(k) に対しては次の公式が成り立ちます。

Sm( k + 1 ) - Sm( k )={ 1m + 2m + ... + km + ( k + 1 )m } - { 1m + 2m + ... + km }
=( k + 1 )m

k は自然数なので Sm(k) は離散値を取りますが、明らかに多項式の形をとるため実数にまで範囲を広げて微分しても問題はありません。そこで、上式を微分してみます。

Sm'( k + 1 ) - Sm'( k ) = m( k + 1 )m-1

この式について、0 ≤ k ≤ n - 1 の間で総和を計算すると、

(左辺)=Σk{0→n-1}( Sm'( k + 1 ) - Sm'( k ) )
=( Sm'( 1 ) - Sm'( 0 ) ) + ( Sm'( 2 ) - Sm'( 1 ) ) + ... + ( Sm'( n ) - Sm'( n - 1 ) )
=Sm'( n ) - Sm'( 0 )
(右辺)=Σk{0→n-1}( m( k + 1 )m-1 )
=k{1→n}( km-1 ) = mSm-1( n )

よって、

Sm'( n ) - Sm'( 0 ) = mSm-1( n )

ここで、先ほど得られた結果から Sm(n) は次数の最大が m + 1 になることがわかるので

Sm(n) = Σk{0→m+1}( bmknk )

とすると、Sm'( 0 ) は次数 1 の係数を表すので bm1 (定数) になります。従って、

Sm'( n ) = mSm-1( n ) + bm1

これをさらに微分していくと、

Sm(2)( n )=mSm-1'( n )
=m( ( m - 1 )Sm-2( n ) + bm-1,1 )
Sm(3)( n )=m( m - 1 )Sm-2'( n )
=m( m - 1 ){ ( m - 2 )Sm-3( n ) + bm-2,1 )
:
Sm(j)( n )=m( m - 1 )...( m - j + 2 )Sm-j+1'( n )
=m( m - 1 )...( m - j + 2 ){ ( m - j + 1 )Sm-j( n ) + bm-j+1,1 )
=mPj Sm-j( n ) + mPj-1 bm-j+1,1

但し、mPj順列を表し、mPj = m! / ( m - j )!

Sm(n) の漸化式を見ると、定数項は必ずゼロになることが分かります。従って、Sm(0) = 0 となります。よって、

Sm(j)( 0 ) = mPj-1 bm-j+1,1

以上から、Sm(n) の「マクローリン展開」は

Sm( n )=Σj{1→m+1}( Sm(j)( 0 ) nj / j! )
=Σj{1→m+1}( mPj-1 bm-j+1,1・nj / j! )
=Σj{1→m+1}( { m! / ( m - j + 1 )! j! } bm-j+1,1・nj )
=Σj{1→m+1}( { 1 / ( m + 1 ) }{ ( m + 1 )! / ( m + 1 - j )! j! } bm-j+1,1・nj )
=Σj{1→m+1}( C( m + 1, j ) bm-j+1,1・nj ) / ( m + 1 )

ここで、k = m - j + 1 とすると j = m + 1 - k で、j が 1 から m + 1 まで変化するとき k は m から 0 まで変化するので

Sm( n )=Σk{m→0}( C( m + 1, m + 1 - k ) bk1・nm+1-k ) / ( m + 1 )
=Σk{0→m}( C( m + 1, k ) bk1・nm+1-k ) / ( m + 1 )

よって、Sm( n ) の m + 1 - k 次の係数が { C( m + 1, k ) / ( m + 1 ) } bk1 という値で表されることになります。ここで、bk1 は Sk(n) の一次項の係数になります。この数は「ベルヌーイ数 ( Bernoulli Number )」と呼ばれ、その導き方から分かるように全て有理数となります。また、べき乗の総和をベルヌーイ数を使った多項式で表したものは「ファウルハーバーの公式 ( Faulhaber's Formula )」または「ベルヌーイの公式 ( Bernoulli's Formula )」と呼ばれています。

bk1 を新たに bk と表すことにして、得られた漸化式に n = 1 を代入すると

Sm( 1 ) = Σk{0→m}( C( m + 1, k ) bk ) / ( m + 1 ) = 1 より

Σk{0→m}( C( m + 1, k ) bk ) = m + 1

これを使って bk を求めてみます。

C( 1, 0 ) b0 = 1 より b0 = 1

C( 2, 0 ) b0 + C( 2, 1 ) b1 = 1 + 2b1 = 2 より b1 = 1 / 2

C( 3, 0 ) b0 + C( 3, 1 ) b1 + C( 3, 2 ) b2 = 1 + 3 / 2 + 3b2 = 3 より b2 = 1 / 6

C( 4, 0 ) b0 + C( 4, 1 ) b1 + C( 4, 2 ) b2 + C( 4, 3 ) b3 = 1 + 2 + 1 + 4b3 = 4 より b3 = 0

C( 5, 0 ) b0 + C( 5, 1 ) b1 + C( 5, 2 ) b2 + C( 5, 3 ) b3 + C( 5, 4 ) b4 = 1 + 5 / 2 + 5 / 3 + 5b4 = 5 より b4 = - 1 / 30

ここで、C( 2, 1 ) b1 = 1, C( 3, 1 ) b1 = 3 / 2, ... C( m + 1, 1 ) b1 = ( m + 1 ) / 2 なので、右辺の m + 1 を減算することで必ず - ( m + 1 ) / 2 となります。これを利用して、

b0 = 1

Σk{0→m}( C( m + 1, k ) bk ) = 0 ( m > 0 )

と変形しても、b1 = -1 / 2 となるだけでそれ以降は上記と同じ値が得られます。ベルヌーイ数を計算する場合はこちらの漸化式が利用され、b1 = -1 / 2 で表します。


数列 { ak } = a0, a1, ... を係数とするべき級数

G(x) = a0 + a1x + a2x2 + ... + akxk + ... = Σk{0→∞}( akxk )

は、数列 { ak } の「母関数 ( Generating Function ; または生成関数 )」といいます。数列は離散値なのに対し、母関数で表すことで連続的な値をとる関数として扱うことができるようになるので、関数の持つ性質 ( 例えば微積分や極限など ) を利用して数列の性質を解明する目的で母関数は用いられます。上記形式の母関数は「通常型母関数 ( Ordinary Generating Function )」と呼ばれ、他にも次のような種類のものがあります。

EG(x) = a0 + a1x + a2x2 / 2! + ... + akxk / k! + ... = Σk{0→∞}( akxk / k! ) [ 指数型母関数(Exponential Generating Function) ]

PG(x) = a0e-x + a1e-xx + a2e-xx2 / 2! + ... + ake-xxk / k! + ... = Σk{0→∞}( ake-xxk / k! ) [ ポアソン母関数(Poisson Generating Function) ]

通常型母関数において { ak } = { 1, 1, 1, ... } とすれば、G(x) = 1 + x + x2 + ... となるので、これは初項 1、公比 x の等比級数を表します。第 n 項までの和は

G(x,n) = 1 + x + x2 + ... + xn

これに x を掛けると

xG(x,n) = x + x2 + x3 + ... + xn+1

両式の差分を計算すると

G(x,n)=1+x+x2+x3+ ... +xn
xG(x,n)=x+x2+x3+ ... +xn+xn+1
( 1 - x )G(x,n)=1xn+1

よって、G(x,n) = ( 1 + xn+1 ) / ( 1 - x ) となり、|x| < 1 ならば右辺は 1 / ( 1 - x ) ( n → ∞ ) となるので、

Σk{0→∞}( xk ) = 1 / ( 1 - x ) ( 但し |x| < 1 )

という公式が得られます。、G(x) の両辺を微分すると、

1 + 2x + 3x2 + ... + nxn-1 + ... = 1 / ( 1 - x )2

両辺に x を掛ければ

x + 2x2 + 3x3 + ... + nxn + ... = x / ( 1 - x )2

これは、自然数を数列とした場合の母関数に対する公式になります。同様に微分を続けていけば、平方数・立方数を数列とした母関数の公式も求めることができます。ところで、二項定理から

C( n, 0 ) + C( n, 1 ) x + C( n, 2 ) x2 + ... + C( n, n ) xn = ( 1 + x )n

なので、これは二項係数を数列とした場合の母関数に対する公式でもあります。

指数型母関数を見ると、{ ak } = { 1, 1, 1, ... } とすれば EG(x) = 1 + x + x2 / 2! + ... + xk / k! + ... = Σk{0→∞}( xk / k! ) となり、この右辺は指数関数 ex のマクローリン展開です。「指数型」と名付けられたのはこの性質のためです。

ベルヌーイ数 bk を求める漸化式

Σk{0→m}( C( m + 1, k ) bk ) = 0

の左辺を 0 から m - 1 までの和に置き換えた式からなる数列 { am } = { Σk{0→m-1}( C( m, k ) bk ) } の指数型母関数として、

EG(x)=Σm{1→∞}( Σk{0→m-1}( C( m, k ) bk ) xm / m! )
=Σk{0→0}( C( 1, k ) bk ) x + Σk{0→1}( C( 2, k ) bk ) x2 / 2! + Σk{0→2}( C( 3, k ) bk ) x3 / 3! + ...

を定義します。総和は 1 から始まるので、母関数は定数項を持ちません。このとき、

a1 = C( 1, 0 ) b0 = 1

am = Σk{0→m-1}( C( m, k ) bk ) = 0 ( m > 1 )

なので、

EG(x) = x

となります。一方、

EG(x)=Σm{1→∞}( Σk{0→m-1}( C( m, k ) bk ) xm / m! )
=Σm{1→∞}( Σk{0→m-1}( { m! / k!( m - k )! } bk ) xm / m! )
=Σm{1→∞}( Σk{0→m-1}( ( bk / k! ) { 1 / ( m - k )! } ) xm )

母関数の積の公式 ( 補足 2 ) から上式は

EG(x)=Σm{0→∞}( bm xm / m! ) Σm{1→∞}( xm / m! )
=Σm{0→∞}( bm xm / m! ) ( ex - 1 )

こうして得られた二式から

Σm{0→∞}( bm xm / m! ) = x / ( ex - 1 )

で表すことができます。この式から、ベルヌーイ数 bk は関数 x / ( ex - 1 ) のマクローリン展開における、次数 k の項の係数を表すことになります。

ベルヌーイ数を求めるためのサンプル・プログラムを以下に示します。

/*
  AccurateCombination : 組み合わせ ( n 個の要素から r 個を選ぶ場合の数 ) の計算

  nCr = n! / r!( n - r )! を正確に計算する。
  計算可能な範囲は戻り値の型 Res に依存し、Res の取りうる値の範囲を超えた場合は正しい結果は得られない。

  n : 要素数
  r : 要素から選択する数
  戻り値 : 組み合わせの計算結果
*/
template< class Res, class T >
  Res AccurateCombination( T n, T r )
{
  if ( n < r ) return( Res() );   // n < r なら nCr = 0
  if ( r < 0 ) return( Res() );   // nC-r = 0

  if ( r > n - r ) r = n - r; // nCn-r = nCr

  if ( r == 0 ) return( Res( 1 ) );  // nC0 = 1
  if ( r == 1 ) return( Res( n ) );  // nC1 = n

  // まずは順列 n( n - 1 )...( n - r + 1 ) を求める
  Res ans = n;
  for ( T t = n - r + 1 ; t < n ; ++t )
    ans *= t;

  // 階乗 r! を求める
  Res fact = r;
  for ( --r ; r > 1 ; --r )
    fact *= r;

  ans /= fact;

  return( ans );
}

/*
  AccurateBernoulliNum : ベルヌーイ数 Bn を求める

  ベルヌーイ数の計算に利用する組み合わせ(二項係数)は AccurateCombination を使って正確に求めている。

  n : 何番目のベルヌーイ数か?
  戻り値 : ベルヌーイ数 Bn
*/
template< class Res, class I >
  Res AccurateBernoulliNum( I n )
{
  if ( n < I() ) return( Res() );
  if ( n == I() ) return( Res( 1 ) );

  I np( n + 1 );
  //Res b = Res( n + 1 );
  Res b = Res();
  for ( I i = I() ; i < n ; ++i )
    b -= Res( AccurateCombination< Res, I >( np, i ) ) * AccurateBernoulliNum< Res, I >( i );

  b /= Res( np );

  return( b );
}

ベルヌーイ数の計算は、関数 AccurateBernoulliNum の中で行います。また、組み合わせの計算が必要となるため、AccurateCombination 関数を実装しています。どちらも「正確に」値を計算しますが、利用する型はテンプレート引数で指定するようになっているので、例えば浮動小数点数を利用した場合は近似値として結果が得られることになります。AccurateBernoulliNum においてテンプレート引数 Res は戻り値 ( ベルヌーイ数 ) の型を表し、有理数や浮動小数点数の利用を想定しています。また、I は引数 ( 何番目のベルヌーイ数か ) を表す型で、整数型の利用を想定しています。AccurateCombination については戻り値 ( 組み合わせ ) と引数 ( 要素数と選択数 ) それぞれで型を分けていますが、どちらも整数型であることを想定しています。

ベルヌーイ数は有理数なので、「数値演算法 (5) 有理数と無理数の演算」の中の「2) 有理数の表現方法」で作成した BigNum::Rational クラスを利用することができます。このクラスを使って計算した結果は次のようになります。

表 4-1. ベルヌーイ数
nbnnbn
01105/66
1-1/2110
21/612-691/2730
30130
4-1/30147/6
50150
61/4216-3617/510
70170
8-1/301843867/798
90190

n = 1 を除き、奇数番目のベルヌーイ数は全てゼロになっています。また、偶数番目のベルヌーイ数は正負が交互に入れ替わっています。

ところで、サンプル・プログラムで、結果を格納するための変数 b の初期値をゼロにしている記述の上に n + 1 で初期化する記述があって、こちらはコメントアウトされています。ここで、n + 1 で初期化する方を有効にした場合、b1 の値の正負が逆転するだけで、他の値は全て同じになります。これは先述した通り、漸化式

Σk{0→m}( C( m + 1, k ) bk ) = m + 1

において、C( m + 1, 1 ) b1 = ( m + 1 ) / 2 となることから、両辺から m + 1 を減算した上で b1 の符号を反転しても漸化式が成り立つためです。ここで、

am = Σk{0→m-1}( C( m, k ) bk ) = m

とした場合の { am } を係数とした指数型母関数を求めると、

EG(x)=Σk{0→0}( C( 1, k ) bk ) x + Σk{0→1}( C( 2, k ) bk ) x2 / 2! + Σk{0→2}( C( 3, k ) bk ) x3 / 3! + ...
=x + 2x2 / 2! + 3x3 / 3! + ...
=x( Σm{0→∞}( xm / m! ) ) = xex

となるので、

Σm{0→∞}( bm xm / m! ) = xex / ( ex - 1 )

但し、この時は b1 = 1 / 2 になります。

ベルヌーイ数の名前は、ヨーロッパにおいて少なくとも八人の優れた数学者を輩出したとされる数学者一族ベルヌーイ家が由来となっています。ベルヌーイ家の一人「ヤコブ・ベルヌーイ ( Jakob Bernoulli )」が、べき乗の総和を求める問題の一般解の中でベルヌーイ数を使い、その内容は、彼の死後に出版された「推測法 ( Ars Conjectandi )」によって広く知られるようになりました。しかし、ほぼ同時期に日本の数学者「関考和」も独自に同じ結果を得て、その内容は「括要算法」の中で発表されています。


5) オイラー・マクローリンの公式 ( Euler-Maclaurin Formula )

ベルヌーイ数を係数に含んだ次のような多項式を「ベルヌーイ多項式 ( Bernoulli Polynomials )」といいます。

Bm(x) = Σk{0→m}( C( m, k )bk xm-k )

Bm(x) の定数項は bm になるので、Bm(0) = bm が成り立ちます。m の値をいくつか決めて多項式の実際の式を求めると次のようになります。

B0(x) = b0 = 1

B1(x) = C( 1, 0 )b0x + C( 1, 1 )b1 = x - 1/2

B2(x) = C( 2, 0 )b0x2 + C( 2, 1 )b1x + C( 2, 2 )b2 = x2 - x + 1/6

ここで、ベルヌーイ多項式に関するいくつかの性質を証明しておきます。まず、Bm(x) を微分すると、

B'm(x)=Σk{0→m-1}( C( m, k )bk ( m - k )xm-k-1 )
=Σk{0→m-1}( { m!・( m - k ) / k! ( m - k )! } bk xm-k-1 )
=m Σk{0→m-1}( { ( m - 1 )! / k! ( m - 1 - k )! } bk xm-1-k )
=m Σk{0→m-1}( C( m - 1, k )bk xm-1-k ) = mBm-1(x)

という関係式が得られます ( べき乗の総和について得られた関係式 Sm'(n) = mSm-1(n) + bm とよく似た形となっています )。また、ベルヌーイ多項式に対する指数型母関数は、

EG(x)=Σm{0→∞}( Bm(x)・tm / m! )
=Σm{0→∞}( Σk{0→m}( C( m, k )bk xm-k )・tm / m! )
=Σm{0→∞}( Σk{0→m}( { m! / k!・( m - k )!・m! } bk xm-k tm ) )
=Σm{0→∞}( Σk{0→m}( { bk tk / k! }{ (tx)m-k / ( m - k )! } )
=Σm{0→∞}( bm tm / m! )Σm{0→∞}( (tx)m / m! )[母関数の積の公式 ( 補足 2 ) より]

ベルヌーイ数 bk を求める漸化式 Σk{0→m}( C( m + 1, k ) bk ) = 0 の指数型母関数から Σm{0→∞}( bm tm / m! ) = t / ( et - 1 ) であることはすでに前節で示しました。また、ex のマクローリン展開から Σm{0→∞}( (tx)m / m! ) = etx となるので、

EG(x) = tetx / ( et - 1 )

と求めることができます。これを利用すると、

EG(1) - EG(0)=Σm{0→∞}( { Bm(1) - Bm(0) }・tm / m! )
=tet / ( et - 1 ) - t / ( et - 1 )
=t( et - 1 ) / ( et - 1 ) = t

なので、係数を比較することで、m = 1 を除いて Bm(0) = Bm(1) が成り立つことが分かります ( m = 1 の場合は B1(1) - B1(0) = 1, B1(0) = b1 = -1/2 より B1(0) = - B1(1) = - 1/2 になります )。Bm(0) = bm なので、これらはベルヌーイ数と等しいということも意味しています。また、

EG(1)=Σm{0→∞}( Bm(1)・tm / m! )
=tet / ( et - 1 )
=-t / ( e-t - 1 )
=Σm{0→∞}( Bm(0)・(-t)m / m! )

なので、m = 1 以外の奇数次の項は Bm(0) = Bm(1) であると同時に Bm(0) = - Bm(1) でもあり、従って Bm(0) = Bm(1) = 0 が成り立つことになります。つまり、奇数番目のベルヌーイ数は m = 1 を除いて全てゼロになります。

以上、ベルヌーイ多項式の性質をまとめると、

B'm(x) = mBm-1(x) [ベルヌーイ多項式の微分] --- (1)

EG(x) = tetx / ( et - 1 ) [指数型母関数] --- (2)

Bm(0) = Bm(1) = bm ( m > 1 ) --- (3)

B2m+1(0) = B2m+1(1) = b2m+1 = 0 ( m > 0 ) --- (4)

ある関数 f(x) の 0 から 1 までの定積分 ∫{0→1} f(x) dx において、B0(x) = 1 なので ∫{0→1} B0(x) f(x) dx と強引に代入します。ここで、微分に関する関係式から B'1(x) = B0(x) が成り立つので、部分積分法 ∫f'(x)g(x)dx = f(x)g(x) - ∫f(x)g'(x)dx を利用して

∫{0→1} B0(x) f(x) dx=∫{0→1} B'1(x) f(x) dx
=[ B1(x) f(x) ]{0→1} - ∫{0→1} B1(x) f(1)(x) dx
={ B1(1) f(1) - B1(0) f(0) } - ∫{0→1} B1(x) f(1)(x) dx

上式において、f(m)(x) は m 階導関数を表すものとします。B1(0) = - B1(1) = -1/2 なので、

∫{0→1} B0(x) f(x) dx = (1/2){ f(0) + f(1) } - ∫{0→1} B1(x) f(1)(x) dx

この操作は何度も繰り返すことができて、その度に二つの式に分解されていきます。∫{0→1} Bm(x) f(m)(x) dx に対しては B'm+1(x) = ( m + 1 )Bm(x) が成り立つので、

∫{0→1} Bm(x) f(m)(x) dx=∫{0→1} B'm+1(x) f(m)(x) / ( m + 1 ) dx
=[ Bm+1(x) f(m)(x) / ( m + 1 ) ]{0→1} - ∫{0→1} Bm+1(x) f(m+1)(x) / ( m + 1 ) dx
=bm+1{ f(m)(1) - f(m)(0) } / ( m + 1 ) - ∫{0→1} Bm+1(x) f(m+1)(x) / ( m + 1 ) dx

上記操作の繰り返しの中で、奇数番号のベルヌーイ数が 1 を除いて全てゼロであることから偶数番号のベルヌーイ数だけが残ることになり、以下のような式が得られることになります。

∫{0→1} f(x) dx=(1/2){ f(0) + f(1) } - b2{ f(1)(1) - f(1)(0) } / 2 - b4{ f(3)(1) - f(3)(0) } / 4! - ... - b2m{ f(2m-1)(1) - f(2m-1)(0) } / (2m)! + ∫{0→1} B2m(x) f(2m)(x) / (2m)! dx
=(1/2){ f(0) + f(1) } - Σk{1→m}( b2k{ f(2k-1)(1) - f(2k-1)(0) } / (2k)! ) + ∫{0→1} B2m(x) f(2m)(x) / (2m)! dx

定積分を行う区間を任意の範囲 [ a, a + h ] としたとき、y = ( x - a ) / h とすれば dx = h・dy で、y は [ 0, 1 ] の区間に変換されます。また、x から y への変数変換によって、f(x) の y による微分を行うと h が係数として現れる ( df/dy = (df/dx)・(dx/dy) = h・(df/dx) ) ので、

∫{a→a+h} B0( ( x - a ) / h ) f(x) dx=∫{0→1} B0(y) f( hy + a ) hdy
=h[ B1(y) f( hy + a ) ]{0→1} - h2∫{0→1} B1(y) f(1)( hy + a ) dy
=(h/2){ f(a) + f(a+h) } - h2∫{0→1} B1(y) f(1)( hy + a ) dy

この操作を繰り返すと

∫{a→a+h} f(x) dx = (h/2){ f(a) + f(a+h) } - Σk{1→m}( b2kh2k{ f(2k-1)(a+h) - f(2k-1)(a) } / (2k)! ) + h2m+1∫{0→1} B2m(y) f(2m)( hy + a ) / (2m)! dy

になります。区間を、[ a, a + h ], [ a + h, a + 2h ], ... , [ a + ( n - 1 )h, a + nh ] と細かく分割してた上で、上記操作を各区間ごとに行ってその総和を取ったとき、

∫{a→a+nh} f(x) dx=Σi{0→n-1}( ∫{a+ih→a+(i+1)h} f(x) dx )
=Σi{0→n-1}( (h/2){ f(a+ih) + f(a+(i+1)h) } - Σk{1→m}( b2kh2k{ f(2k-1)(a+(i+1)h) - f(2k-1)(a+ih) } / (2k)! )
+ h2m+1∫{0→1} B2m(yi) f(2m)( h( i + yi ) + a ) / (2m)! dyi )

但し、yi = ( x - a - ih ) / h

ここで、

Σi{0→n-1}( (h/2){ f(a+ih) + f(a+(i+1)h) } )=(h/2)[ { f(a) + f(a+h) } + { f(a+h) + f(a+2h) } + ... + { f(a+(n-1)h) + f(a+nh) } ]
=h{ f(a) / 2 + Σi{1→n-1}( f(a+ih) ) + f(a+nh) / 2 }

これは台形則による定積分値の求め方と同じなので、Tn とおきます。また、

Σi{0→n-1}( Σk{1→m}( b2kh2k{ f(2k-1)(a+(i+1)h) - f(2k-1)(a+ih) } / (2k)! ) )
=Σk{1→m}( ( b2kh2k / (2k)! )Σi{0→n-1}( f(2k-1)(a+(i+1)h) - f(2k-1)(a+ih) ) )
=Σk{1→m}( ( b2kh2k / (2k)! ){ f(2k-1)(a+nh) - f(2k-1)(a) } )

になります。残る剰余項については、

R=Σi{0→n-1}( h2m+1∫{0→1} B2m(yi) f(2m)( h( i + yi ) + a ) / (2m)! dyi )
=( h2m+1 / (2m)! )Σi{0→n-1}( ∫{a+ih→a+(i+1)h} B2m( ( x - a - ih ) / h ) f(2m)(x) (1/h)dx )
=( h2m / (2m)! )∫{a→a+nh} B2m( ( x - a ) / h - [ ( x - a ) / h ] ) f(2m)(x) dx

と表します。但し [ ( x - a ) / h ] は ( x - a ) / h を超えない最大の整数を表します。これは、ベルヌーイ多項式の積分範囲が常に 0 〜 1 の範囲になることを表しています。

以上の内容から、

∫{a→a+nh} f(x) dx = Tn - Σk{1→m}( ( b2kh2k / (2k)! ){ f(2k-1)(a+nh) - f(2k-1)(a) } ) + R

項を置き換えると

Tn - ∫{a→a+nh} f(x) dx = Σk{1→m}( ( b2kh2k / (2k)! ){ f(2k-1)(a+nh) - f(2k-1)(a) } ) - R

右辺は、台形則で求めた近似値と実際の定積分値との差を表すことになり、これによって誤差を評価することができることを意味しています。この公式を「オイラー・マクローリンの公式 ( Euler-Maclaurin Formula )」といいます。この公式は、「レオンハルト・オイラー ( Leonhard Euler )」と「コリン・マクローリン ( Colin Maclaurin )」がそれぞれ独立に発見したことからその名が付けられています。マクローリンは、例の「マクローリン展開」の名でも有名な数学者です。

ベルヌーイ数を含む総和部分を Tn から減算すれば精度が上がることになり、m を大きくすればそれだけ誤差も小さく抑えることができます。m = 1, 2 の場合の式は、次のようになります。

∫{a→a+nh} f(x) dx = Tn - ( h2 / 12 ){ f(1)(a+nh) - f(1)(a) }

∫{a→a+nh} f(x) dx = Tn - ( h2 / 12 ){ f(1)(a+nh) - f(1)(a) } + ( h4 / 720 ){ f(3)(a+nh) - f(3)(a) }

残念ながら、上式を利用するためには関数 f(x) の導関数を求めておく必要があるので、任意の関数に対して適用することは簡単にはできません。あらかじめ関数が決まっていて、その高階導関数に対する値が簡単に求められれば、少ない分割数でかなり精度の高い近似式が得られるようになります。例として、指数関数 ex に対して適用した結果を以下に示します。ex は何回微分しても関数の形が変化しないため、非常に簡単に結果を調べることができます。

表 4-2. ∫{0→1} ex dx のオイラー・マクローリンの公式による補正結果
n台形則補正1補正2
計算結果誤差計算結果誤差計算結果誤差
11.859140914230.140859085771.71595076186-0.002331066601.718337264400.00005543594
51.724005619780.005723791321.71827801369-0.000003814771.718281832090.00000000363
101.719713491390.001431662931.71828158987-0.000000238591.718281828520.00000000006
151.718918182000.000636353541.71828178132-0.000000047141.718281828460.00000000000
201.718639788930.000357960471.71828181354-0.000000014911.718281828460.00000000000
251.718510926590.000229098131.71828182235-0.000000006111.718281828460.00000000000

「補正1」は一階導関数、「補正2」は三階導関数の値まで利用した補正を行った結果です。「補正2」の結果を見ると、10 個程度の分割でかなり精度のよい近似値が得られているので、台形則のみで計算した場合と比較すると圧倒的に早く収束させることができることが分かります。


6) スターリングの公式 (Stirling's Formula)

階乗は、順列や組み合わせの計算などでよく利用されます。階乗の計算は 1 から順番に自然数を掛け合わせていくことで計算することができますが、すぐに巨大な数値になるため正確な値を計算するためには「多倍長整数」による演算が必要になります。例えば、100 個の要素を並べる場合の数は 100! で、

100! =  93,326,215,443,944,152,681,699,238,856,266,700,490,715,968,264,381,621,468,592,
       963,895,217,599,993,229,915,608,941,463,976,156,518,286,253,697,920,827,223,758,
       251,185,210,916,864,000,000,000,000,000,000,000,000

という 158 桁の巨大な数になります。コンピュータなどなかった時代は階乗を手計算で求める必要があったので、このような乗算を毎回繰り返すようなことはしたくないわけで、必然的に近似値を求めるための手法が編み出されました。このとき、数値積分法が利用されています。

まず、階乗の対数をとります。

ln(n!) = ln(1) + ln(2) + ... + ln(n) = Σk{1→n}( ln(k) )

一方、

∫{1→n} ln(x) dx=[ x・ln(x) ]{1→n} - ∫{1→n} x・( 1 / x ) dx
=n・ln(n) - [ x ]{1→n}
=n・ln(n) - n + 1

上記は、f(x) = x、g(x) = ln(x) として、部分積分法 ∫ f'(x)g(x) dx = f(x)g(x) - ∫ f(x)g'(x) dx を利用しています。

前者は区分求積法によって ∫{1→n} ln(x) dx の値を近似計算したものと考えれば、両者の値は近いことが推測できます。よって、

ln(n!) ≅ n・ln(n) - n + 1

より

n! ≅ exp( n・ln(n) - n + 1 ) = e( n / e )n

∫{1→n} ln(x) dx に対して台形則を利用した場合は、

∫{1→n} ln(x) dx=ln(1) / 2 + Σi{2→n-1}( ln(i) ) + ln(n) / 2
=Σi{1→n}( ln(i) ) - ln(n) / 2

となるので、

ln(n!) ≅ n・ln(n) - n + 1 + ln(n) / 2

n! ≅ exp( n・ln(n) - n + 1 + ln(n) / 2 ) = e√n ( n / e )n

大雑把な近似式として、無視できる部分を全て除外した

ln(n!) ≅ n・ln(n) - n

n! ≅ ( n / e )n

という式が用いられることもあります。n が増大するにしたがって分割数も増大するので、近似値は実際の値に近づいていきます。つまり、n の増大に伴い、ln(n!) と n・ln(n) - n は値が近づいていき、n → ∞ においては両者の差が一定の値に収束することが予想され、実際にそうなります。以下で、その証明方法について説明します。

オイラー・マクローリンの公式を ∫{1→n} ln(x) dx に適用してみます。

∫{1→n} ln(x) dx={ ln(1) / 2 + Σi{2→n-1}( ln(i) ) + ln(n) / 2 } - ∫{1→n} B1(x-[x]) ln(1)(x) dx
=ln(n!) - ln(n) / 2 - ∫{1→n} B1(x-[x]) / x dx

よって、

n・ln(n) - n + 1 = ln(n!) - ln(n) / 2 - ∫{1→n} B1(x-[x]) / x dx より

ln(n!) - ( n + 1/2 )ln(n) + n = 1 + ∫{1→n} B1(x-[x]) / x dx

上式の左辺および右辺の式を R(n) とします。このとき、

2ln( 2・4・...・2n )=2ln( 2n( 1・2・...・n ) )
=2n・ln(2) + 2ln(n!)
=2n・ln(2) + 2{ ( n + 1/2 )ln(n) - n + R(n) }
=( 2n + 1 ){ ln(n) + ln(2) } - ln(2) - 2n + 2R(n)
=( 2n + 1 )ln(2n) - 2n - ln(2) + 2R(n)
ln( ( 2n + 1 )! )=( ( 2n + 1 ) + 1/2 )ln( 2n + 1 ) - ( 2n + 1 ) + R(2n + 1)
=( 2n + 3/2 )ln( 2n + 1 ) - ( 2n + 1 ) + R(2n + 1)

となるので、両式を辺々引いて

2ln( 2・4・...・2n ) - ln( ( 2n + 1 )! ) = { ( 2n + 1 )ln(2n) - 2n - ln(2) + 2R(n) } - { ( 2n + 3/2 )ln( 2n + 1 ) - ( 2n + 1 ) + R(2n + 1) }

両辺を整理すると

ln( 2・4・...・2n / 1・3・...・( 2n + 1 ) )=( 2n + 1 ){ ln(2n) - ln( 2n + 1 ) } - ln( 2n + 1 ) / 2 - ln(2) + 1 + 2R(n) - R(2n + 1)
ln( 2・4・...・2n / 1・3・...・( 2n - 1 )・( 2n + 1 )1/2 )=-{ ln( ( 1 + 1 / 2n )2n+1 ) } - ln(2) + 1 + 2R(n) - R(2n + 1)

になるので、この式に対して n → ∞ のときの極限を考えます。まず、R(n) について、R(n) - R(n + 1) を計算すると、

R(n) - R(n + 1)={ ln(n!) - ( n + 1/2 )ln(n) + n } - { ln( ( n + 1 )! ) - ( n + 3/2 )ln(n + 1) + n + 1 }
=ln( n! / ( n + 1 )! ) + ( n + 1/2 )ln( ( n + 1 ) / n ) + ln( n + 1 ) - 1
=-ln( n + 1 ) + ( n + 1/2 )ln( 1 + 1 / n ) + ln( n + 1 ) - 1
=ln( ( 1 + 1/n )n ) + (1/2)ln( 1 + 1/n ) - 1

ネイピア数 e の定義から lim{n→∞}( 1 + 1/n )n = e なので、上記の値は n → ∞ でゼロに収束します。つまり、R(n) はある値に収束することになるので、その値を C とします。また、

ln( ( 1 + 1 / 2n )2n+1 ) = ln( ( 1 + 1 / 2n )2n ) + ln( 1 + 1 / 2n ) → 1 ( n → ∞ )

となるため、

(右辺) = C - ln(2)

になります。左辺は、以下に示す「ウォリス積 ( 補足 3 )」を使って正確な値を求めることができます ( 先程 ln( 2・4・...・2n ) と ln( ( 2n + 1 )! ) が唐突に現れたのはこれを利用するためです )。

Πk{1→∞}( (2k)2 / ( 2k - 1 )( 2k + 1 ) ) = π / 2

ウォリス積を利用すると、

{ 2・4・...・2n / 1・3・...・( 2n - 1 )・( 2n + 1 )1/2 }2
(2)2・(4)2・...・(2n)2 / { 1・3・...・( 2n - 1 ) }・{ 3・5・...・( 2n - 1 )・( 2n + 1 ) }
=Πk{1→n}( (2k)2 / ( 2k - 1 )( 2k + 1 ) )
π / 2 ( n → ∞ )

となるので、

(左辺) = (1/2)ln( π / 2 )

(左辺) = (右辺) なので、C の値を求めることができて、

C = (1/2)ln( π / 2 ) + ln(2) = (1/2)ln( 2π )

よって、

R(n) = ln(n!) - ( n + 1/2 )ln(n) + n → C = (1/2)ln( 2π ) ( n → ∞ )

となって、

lim{n→∞}( ln(n!) ) = ( n + 1/2 )ln(n) - n + (1/2)ln( 2π )

つまり、n が充分に大きければ、以下の近似式が成り立つことになります。

ln(n!) ≅ ( n + 1/2 )ln(n) - n + (1/2)ln( 2π )

n! ≅ ( 2πn )1/2( n / e )n

この式は、「スターリングの公式 ( Stirling's Formula )」として知られる有名な近似式です。しかし、公式を最初に発見したのは「ド・モアブルの定理」で有名な「アブラーム・ド・モアブル ( Abraham de Moivre )」で、最初は

n! ≅ Cnn+1/2e-n ( C:定数 )

であることまでが示されていました。スターリングの名は、その後「ジェイムズ・スターリング ( James Stirling )」が C = ( 2π )1/2 であることを示したことから付けられたようです。


ところで、

R(n) = 1 + ∫{1→n} B1(x-[x]) / x dx

でもあり、これを使って R(n) - R(M) (但し n < M) を計算すると、

R(n) - R(M)={ 1 + ∫{1→n} B1(x-[x]) / x dx } - { 1 + ∫{1→M} B1(x-[x]) / x dx }
=- ∫{n→M} B1(x-[x]) / x dx
=[ - B2(x-[x]) / 2x ]{n→M} - ∫{n→M} B2(x-[x]) / 2x2 dx
=( b2 / 2 ){ ( 1 / n ) - ( 1 / M ) } + ( b4 / 3・4 ){ ( 1 / n3 ) - ( 1 / M3 ) } - ∫{n→M} B4(x-[x]) / 4x4 dx
:
=Σk{1→∞}( { b2k / 2k・( 2k - 1 ) }{ ( 1 / n2k-1 ) - ( 1 / M2k-1 ) } )

M → ∞ とすれば、R(M) → ( 2π )1/2 であり、右辺の M が入った項は無視することができるので、

R(n) = (1/2)ln( 2π ) + Σk{1→∞}( { b2k / 2k・( 2k - 1 )! }{ ( 1 / n2k-1 ) } )

と表すことができます。右辺の総和部分のいくつかを展開してみると

R(n) = (1/2)ln( 2π ) + 1 /12n - 1 / 360n3 + 1 / 1260n5 - 1 / 1680n7 + 1 / 1188n9 - ...

になります。よって、スターリングの公式は次のように表すこともできます。

ln(n!) ≅ ( n + 1/2 )ln(n) - n + (1/2)ln( 2π ) + Σk{1→∞}( { b2k / 2k・( 2k - 1 )! }{ ( 1 / n2k-1 ) } )

n! ≅ ( 2πn )1/2( n / e )n exp( Σk{1→∞}( { b2k / 2k・( 2k - 1 )! }{ ( 1 / n2k-1 ) } ) )

この式は、n がそれほど大きくない場合でもある程度高い精度が得られる近似式になります。


実際に計算を行った結果を以下に示します。対象の値は 10!, 100!, 200!, 500!, 1000! の 5 種類です。

表 6-1. 10! の近似値計算結果
計算式計算結果真値との比率
n!3628800-
( n / e )n4.53999297624849e+050.12511003572113
e ( n / e )n1.23409804086680e+060.34008433665862
e√n ( n / e )n3.90256066509063e+061.07544110038873
( 2πn )1/2 ( n / e )n3.59869561874104e+060.99170403955606
( 2πn )1/2 ( n / e )n exp( 1 /12n )3.62881005142693e+061.00000276990381
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 )3.62879997141301e+060.99999999212219
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 + 1 / 1260n5 )3.62880000021301e+061.00000000005870
 
表 6-2. 100! の近似値計算結果
計算式計算結果真値との比率
n!9.33262154439442e+157-
( n / e )n3.72007597602084e+1560.03986099680915
e ( n / e )n1.01122149261045e+1570.10835342329057
e√n ( n / e )n1.01122149261045e+1581.08353423290569
( 2πn )1/2 ( n / e )n9.32484762526934e+1570.99916701656784
( 2πn )1/2 ( n / e )n exp( 1 /12n )9.33262157031762e+1571.00000000277770
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 )9.33262154439367e+1570.99999999999992
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 + 1 / 1260n5 )9.33262154439442e+1571.00000000000000
 
表 6-3. 200! の近似値計算結果
計算式計算結果真値との比率
n!7.88657867364791e+374-
( n / e )n2.22383597813114e+3730.02819772768592
e ( n / e )n6.04501292882733e+3730.07664937077248
e√n ( n / e )n8.54893926866832e+3741.08398579693798
( 2πn )1/2 ( n / e )n7.88329328644156e+3740.99958342047391
( 2πn )1/2 ( n / e )n exp( 1 /12n )7.88657867638628e+3741.00000000034722
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 )7.88657867364789e+3741.00000000000000
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 + 1 / 1260n5 )7.88657867364789e+3741.00000000000000
 
表 6-4. 500! の近似値計算結果
計算式計算結果真値との比率
n!1.22013682599111e+1134-
( n / e )n2.17651275394853e+11320.01783826786951
e ( n / e )n5.91637506846764e+11320.04848943940088
e√n ( n / e )n1.32294168334786e+11341.08425682691221
( 2πn )1/2 ( n / e )n1.21993348682596e+11340.99983334724367
( 2πn )1/2 ( n / e )n exp( 1 /12n )1.22013682601822e+11341.00000000002222
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 )1.22013682599111e+11341.00000000000000
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 + 1 / 1260n5 )1.22013682599111e+11341.00000000000000
 
表 6-5. 1000! の近似値計算結果
計算式計算結果真値との比率
n!4.02387260077094e+2567-
( n / e )n5.07595889754946e+25650.01261461134872
e ( n / e )n1.37978868332137e+25660.03429006880230
e√n ( n / e )n4.36327492902031e+25671.08434718539159
( 2πn )1/2 ( n / e )n4.02353729203678e+25670.99991667014157
( 2πn )1/2 ( n / e )n exp( 1 /12n )4.02387260078212e+25671.00000000000278
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 )4.02387260077094e+25671.00000000000000
( 2πn )1/2 ( n / e )n exp( 1 /12n - 1 / 360n3 + 1 / 1260n5 )4.02387260077094e+25671.00000000000000

各表の一番上が正確な値 ( 但し有効桁数は 15 桁です ) を表しており、近似計算結果の右側には正確な値との比率が示されています。数が大きくなるほど、どの計算式についても誤差が小さくなっていることが分かります。上側にある近似式 ( n / e )n と e ( n / e )n は大雑把すぎてあまり正確とはいえませんが、他の式に関してはかなり近い値となっています。特に、下側の二つは 10! ですでにほぼ一致しているため、比較的小さい数に対しても精度が高いことがわかります。

ところで、上記検証のために利用した変数は long double 型で、この型によって表現可能な有効桁数は 4900 桁強なので、計算可能な階乗の数は 1700! 程度になります。10000! にもなると、桁数が 35000 を超えるほど巨大な数になります。そのままでは扱いづらいので、通常は対数で表現することになります。


今回は、区分求積法による定積分値の計算法からはじまって、スターリングの公式が区分求積法の考え方を逆利用していることを最後に紹介しました。実は、精度の高い公式は他にもあり、またほとんどの関数に対して収束を早めることのできる万能型の変数変換法なども存在します。さらに広義積分や重積分に対する手法など、なかなか奥深いテーマでもあるので、次の機会にまた取り上げてみたいと思います。


補足 1) 定積分の定義

f(x) は実数値関数で、a ≤ x ≤ b ( つまり閉区間 I = [ a, b ] ) の範囲で連続であるとします。また、この区間では f(x) が有限な範囲の値 M 以下になる( |f(x)| ≤ M )とします。

区間 I 上に有限個の点 a = x0 < x1 < ... < xn-1 < xn = b をとり、その点によって区間 I を分割します。この点を「分点」といいます。分割した各区間の中から代表値を決めて、区間 [ xk-1, xk ] 上の点を ξk ( k = 1, 2, ... n ) としたとき、

RΔ = Σk{1→n}( f(ξk)( xk - xk-1 ) )

は、区間 I の範囲の f(x) の面積に対する近似値となります。これを「リーマン和 ( Riemann Sum )」といいます。分割の仕方も代表値の決め方も任意であり、等間隔に分割する必要も決められた方法で代表値を選ぶ必要もないので、その方法によってリーマン和の値は変化します。

分割の仕方を Δ で表し、各区間での上限を Mk、下限を mk として、これらを代表値としたときのリーマン和を

RM(Δ) = Σk{1→n}( Mk( xk - xk-1 ) )

Rm(Δ) = Σk{1→n}( mk( xk - xk-1 ) )

とすると、-M ≤ mk ≤ Mk ≤ M なので

-M( b - a ) ≤ Rm(Δ) ≤ RΔ ≤ RM(Δ) ≤ M( b - a )

が成り立ちます。

分割の仕方が Δ1 と Δ2 の二つあって、それぞれに対する上で定義したリーマン和を RM1), Rm1) と RM2), Rm2) としたとき、二つの分割に対する分点を全て含む分割 Δ3 のリーマン和 RM3), Rm3) との大小関係はどのようになるかを考えます。Δ1 を基準に考えると、Δ1 の分点の間に Δ2 の分点が存在することになります。Δ1 のある区間 [ x1,m, x1,m+1 ] の間に Δ2 の分点 x2,n, x2,n+1, ... x2,n+k があって、区間 [ x1,m, x1,m+1 ] の上限と下限はそれぞれ M1, m1、区間 [ x2,n+j-1, x2,n+j ] のそれらは M2j, m2j ( j = 1, 2, ... k ) とすると、

m1( x1,m+1 - x1,m ) ≤ Σj{1→k}( m2j( x2,n+j - x2,n+j-1 ) ) ≤ Σj{1→k}( M2j( x2,n+j - x2,n+j-1 ) ) ≤ M1( x1,m+1 - x1,m )

が成り立ちます。また、逆に Δ2 を基準とすれば、同様に考えて

m2( x2,m+1 - x2,m ) ≤ Σj{1→k}( m1j( x1,n+j - x1,n+j-1 ) ) ≤ Σj{1→k}( M1j( x1,n+j - x1,n+j-1 ) ) ≤ M2( x2,m+1 - x2,m )

となります。全区間の総和をとると、中辺は上側と下側のどちらの式についても Rm3) ≤ RM3) であることを表しているので、

Rm1) ≤ Rm3) ≤ RM3) ≤ RM2)

(または Rm2) ≤ Rm3) ≤ RM3) ≤ RM1) )

つまり、任意の分割 Δ, Δ' に対して Rm(Δ) ≤ RM(Δ') となります。簡単に言えば、どのように分割の仕方を変えてみても、総和の上限と下限について大小関係が逆になるような分割の組み合わせは存在しないということです。

図 1-1. リーマン和の大小関係
リーマン和の大小関係

f(x) は区間内で有限な値をとるとしているので、分割をいろいろと変化させる中で必ず RM(Δ) の中の下限と Rm(Δ) の中の上限が存在します。それぞれ inf( RM ), sup( Rm ) ( inf は 下限 ( infimum )、sup は 上限 ( supremum ) の数学用語です ) とすると、上記内容から

sup( Rm ) ≤ inf( RM )

になります。ここで等号が成り立つ時、f(x) は「積分可能」または「可積分」であるといって、その共通の値が f(x) の閉区間 [ a, b ] 上の「定積分」になり、

 b
∫ f(x) dx ( このドキュメントの中では ∫{a→b} f(x) dx と表現しています )
 a

で表されます。例えば f(x) = K (定数) ならば、閉区間 [ a, b ] 上の RΔ はどのような分割の仕方に対しても常に K( b - a ) になるので等号が成り立って可積分であることになります。

分割 Δ の中で、最大となる区間の幅を「Δ の幅」と呼んで、||Δ|| で表します。f(x) が可積分であれば、分割の仕方や代表値の選び方に依存せず、RΔ は ||Δ|| → 0 において一定の値に収束し、逆に lim{||Δ||→0}( RΔ ) = α ならば、f(x) は可積分で α = ∫{a→b} f(x) dx が成り立ちます。||Δ|| を小さくすると、inf( RM ), sup( Rm ) と ∫{a→b} f(x) dx の差がいくらでも小さくなることを厳密に証明した定理は「ダルブーの定理 ( Darboux's Theorem )」と呼ばれ、RM, Rm はそれぞれ「上ダルブー和 ( Upper Darboux Sum )」、「下ダルブー和 ( Lower Darboux Sum )」、さらに inf( RM ), sup( Rm ) が「上ダルブー積分 ( Upper Darboux Integral )」、「下ダルブー積分 ( Lower Darboux Integral )」と名付けられています。リーマン和 RΔ は sup( Rm ) と inf( RM ) の間の値をとるので、lim{||Δ||→0}( RΔ ) = ∫{a→b} f(x) dx が成り立つことになるわけです。

積分可能な関数の条件や、上記説明の厳密な証明法については、解析学の入門書に書かれており、また他のホームページなどでも公開されているので、気になる方は探してみて下さい。参考にした書籍やホームページは、このページの最後に記載しています。


補足 2) 母関数の積

二つの母関数 f(x) = Σn{0→∞}( anxn ) と g(x) = Σn{0→∞}( bnxn ) の積は

f(x)g(x)=Σn{0→∞}( anxnn{0→∞}( bnxn )
=( a0 + a1x + a2x2 + ... )( b0 + b1x + b2x2 + ... )
=a0b0 + ( a0b1 + a1b0 )x + ( a0b2 + a1b1 + a2b0 )x2 + ... + ( a0bn + a1bn-1 + ... + an-1b1 + anb0 )xn + ...
=a0b0 + Σk{0→1}( akb1-k )x + Σk{0→2}( akb2-k )x2 + ... + Σk{0→n}( akbn-k )xn + ...
=Σn{0→∞}( Σk{0→n}( akbn-k )xn )

よって、

Σn{0→∞}( anxnn{0→∞}( bnxn ) = Σn{0→∞}( Σk{0→n}( akbn-k )xn )

が成り立ちます。係数の連番と次数は一致するので、積の中の項の係数は全て、ai と bj の連番 i, j の和がその次数と等しくなります。よって、上記のように展開することができるわけです。


補足 3) ウォリス積 ( Wallis Product )

ウォリス積は「数値演算法 (5) 有理数と無理数の演算」の中でも紹介しており、sin x の乗積展開を使った証明を示してあります ( 証明法 )。ここでは、別の証明法を示します。

Sn = ∫{0→π/2} sinnx dx

とおくと、部分積分法を利用して

Sn=∫{0→π/2} sinx sinn-1x dx
=[ -cosx sinn-1x ]{0→π/2} + ∫{0→π/2} cosx ( n - 1 )sinn-2x cosx dx
=( n - 1 )∫{0→π/2} ( 1 - sin2x ) sinn-2x dx
=( n - 1 )( Sn-2 - Sn )

となるので、漸化式

Sn = { ( n - 1 ) / n }Sn-2

が得られます。よって、

S2n={ ( 2n - 1 ) / 2n }S2n-2
={ ( 2n - 1 ) / 2n }{ ( 2n - 3 ) / ( 2n - 2 ) }S2n-4
:
={ ( 2n - 1 ) / 2n }{ ( 2n - 3 ) / ( 2n - 2 ) }...{ 3 / 4 }{ 1 / 2 }S0
S2n+1={ 2n / ( 2n + 1 ) }S2n-1
={ 2n / ( 2n + 1 ) }{ ( 2n - 2 ) / ( 2n - 1 ) }S2n-3
:
={ 2n / ( 2n + 1 ) }{ ( 2n - 2 ) / ( 2n - 1 ) }...{ 4 / 5 }{ 2 / 3 }S1

より

S2n+1 / S2n=[ { 2n / ( 2n + 1 ) }{ ( 2n - 2 ) / ( 2n - 1 ) }...{ 4 / 5 }{ 2 / 3 }S1 ]
/ [ { ( 2n - 1 ) / 2n }{ ( 2n - 3 ) / ( 2n - 2 ) }...{ 3 / 4 }{ 1 / 2 }S0 ]
={ 2n・2n( 2n - 2 )( 2n - 2 )...・4・4・2・2 }S1 / { ( 2n + 1 )( 2n - 1 )( 2n - 1 )( 2n - 3 )...・5・3・3・1 }S0
=Πk{1→n}( (2k)2 / ( 2k + 1 )( 2k - 1 ) )・( S1 / S0 )

S2n+1 / S2n の、n → ∞ での極限を考えると、0 < x < π/2 では 0 < sinx < 1 なので 0 < S2n+1 < S2n < S2n-1 が成り立って、

1 > S2n+1 / S2n > S2n+1 / S2n-1 = { 2n / ( 2n + 1 ) }S2n-1 / S2n-1 = 1 - 1 / ( 2n + 1 )

よって、S2n+1 / S2n → 1 ( n → ∞ ) になります。最後に S0 = ∫{0→π/2} 1 dx = π/2, S1 = ∫{0→π/2} sinx dx = 1 なので、

Πk{1→∞}( (2k)2 / ( 2k + 1 )( 2k - 1 ) ) = S0 / S1 = π / 2

これで、ウォリス積が証明されました。ちなみに、この一連の証明は、その一部が頻繁に大学入試などで出題されているそうです。

「ウォリス積」の名はイギリスの数学者「ジョン・ウォリス ( John Wallis )」から付けられたものです。ウォリスは、円の面積を求める定積分値 4∫{0→1} ( 1 - x2 )1/2 dx が、二つの定積分値 ∫{0→1} ( 1 - x2 )0 dx と ∫{0→1} ( 1 - x2 )1 dx の間を補間する形で得られるのではないかと類推しました。前者の値は 1、後者の値は 2/3 となり、その幾何平均は [ 1 x ( 2 / 3 ) ]1/2 = ( 2 / 3 )1/2 ≅ 0.8165 で、π / 4 ≅ 0.7854 なので、それぞれ近い値となります。この考え方を発展させて、ウォリス積が誕生したそうです。


<参考文献>
  1. 「数値計算の常識」 伊理正夫・藤野和建 著 (共立出版)
  2. 「基礎課程 解析入門」 野本久夫・岸正倫 著 (サイエンス社)
  3. 「はじめての数論」 ジョセフ・H・シルヴァーマン 著 (ピアソン・エデュケーション)
  4. 「アトムの物理ノート」(http://letsphysics.blog17.fc2.com/) : オイラー・マクローリンの総和公式 (証明)
  5. 「数学のページ」(http://www.igaris.com/math/) : べき乗和の公式(pdf)
  6. MIT COMPUTER SCIENCE AND ARTIFICIAL INTELLIGENCE LABORATORY - Kuat Yessenov
    Kuat's course projects - [18.704] A short expository paper on Euler-Maclaurin formula(pdf)
  7. Wikipedia

[Go Back]前に戻る [Back to HOME]タイトルに戻る
inserted by FC2 system