2. "Implementing QuantLib"の和訳

Appendix A   Odds and Ends 周辺の話題

QuantLibライブラリーを使うにあたって、これまでのChapterで、基本的な事項について説明して来ましたが、読みやすさを重視して、技術的な詳細について延々と述べる事を避けてきました。Douglas AdamsがHitchhiker三部作(銀河ヒッチハイクガイド)の、4番目の本の中で、次のように指摘しています。(注:3部作における4番目の本は変ですが、間違いではありません。そもそも5冊の本からなるのに3部作と呼ばれています。)

「必要以上に詳細な説明は問題です。それは行動を前に進めません。詳細な説明は本を分厚くしますが、あなたが行きたい所にはたどり着かせないでしょう。」

このAppendixは、そういった詳細な事項について、簡単な参考説明を提供しています。しかし、それらを網羅的かつ体系的に説明しようとするものではありません。もし、そのような参考文献が必要なら、QuantLibライブラリーの中にあるReference Manualを参照下さい。

A.1   Basic Types: 基本的なデータ型

QuantLibライブラリーのインターフェースは、(int やfloat やdoubleのような)既に組み込まれているデータ型を使っていません。その代わりに、typedefを使って、Time、Rate、Integer、やSizeといったQuantLibライブラリー特有のデータ型を定義しています。これらのデータ型は、すべて基本的なデータ型に対応付けされています。(以前、型のレンジチェックの機能まで付いたデータ型を定義しようか議論しましたが、それはあきらめました。)さらに、すべての浮動小数点型はRealと定義され、それはdoubleに対応しています。こうすれば、Realに対応するデータ型を定義し直すことで(訳注:例えばdoubleをlong doubleに定義し直して)、整合的にすべてのReal型変数の浮動小数点の精度を同時変更できます。 

原理的には、これにより、浮動小数点の数値精度をユーザーが選択できます。しかし、それが理由で、test-suiteの中で、Real型を、floatやlong doubleで定義し直した場合に、変な計算結果が出るケースが発生してしまいました。typedefを使うメリットは、プログラムコードの意味がより明瞭になる事です。また、私のように、かつて物理学者で次元解析に馴染みがあれば、例えば、\( exp(r)\) とか \(r + s*t\) といった式が Rate  r, Spread   s,  Time   t という型宣言の後に来ると、直ぐに変だと気づく事ができます。(訳注: r が金利、s がスプレッド、t が時間を示しているのが、データ型からすぐ判れば、\(exp(r)\) は、\(exp(rt)\) あるいは \(exp(-rt)\) の間違いで、\(r+s*t\) は \((r+s)*t\) の間違いだとすぐ気づく事ができます) 

もちろん、これらのデータ型は、double と同義語であり、コンパイラーは全く同じものとして扱います。もし、これらのデータ型がより強い型としての機能を持つなら、もっとよかったかも知れません。例えば、あるメソッドが価格Priceを渡された場合とVolatilityを渡された場合に、(いずれもdoubleであるにも拘わらず)異なった型の入力データとして取り扱い、関数のオーバーロードが出来るとか。 

それを可能にする手段として、BOOST_STRONG_TYPEDEFを使う方法があり、これはBoostライブラリーが提供している膨大な機能のひとつです。これは、例えば、次のようにして使います。 

	BOOST_STRONG_TYPEDEF(double, Time)
	BOOST_STRONG_TYPEDEF(double, Rate) 

こうすると、対象とするデータ型と同じように使える、新しいクラス型が創出できます。この方法だと、先ほどのような関数のオーバーロードが可能になります。一方で、この方法の欠点は、すべての型変換が明示的では無い事です。そうすると、古いバージョンとの互換性に問題が発生し、プログラミング上も面倒くさいことになります。 

(注:例えば、単純な構文 Time t =2.0; でもコンパイルエラーになる可能性があります。また、Timeを引数として取る関数f( )についてf(1.5)では無くf(Time(1.5))という風に書く必要があります。) 

 また、(BOOST_STRONG_TYPEDEFのような)マクロによって定義されたクラス型を使うと、すべての演算子をオーバーロードします。そうすると、Time(時間)にRate(金利)を足すような事も出来てしまいます(そう、これもまた次元解析的には問題です)。もし、データ型の体系が、RateとSpreadの足し算やRateとTimeの掛け算は許しても、RateとTimeの足し算に対してはコンパイルエラーを出してくれると助かります。 

 このような事をランタイムでの計算時間に影響を与えず、かつ汎用的に行えるような枠組みは、最初に Barton-Nachman (Dimensional Analysis. In C++ Report, Jan. 1995) によって示されました。このアイデアの発展形は Boost :: Units ライブラリで実装されています。より簡単なバージョンは、私が物理学の世界で働いていた時代に書いたコードがあります(ここでは、説明しませんが、なかなかいい出来です)。しかし、そこまでの機能は、QuantLibの中では必要ないでしょう。QuantLibでは、長さ、体積、質量、時間などの物理量をすべて取り扱う必要は無いからです。 

将来取り入れる可能性がある理想的な妥協点としては、(Boostのstrong typedefのような)Wrapperクラスを実装する方法があります。そのクラスは明示的に、どの演算子がどの型に許されているか定義します。いつもの事ですが、このアイデアを示したのは我々が最初ではありません。次のバージョンのC++に加えるべき機能として、opaque typedefという名前で、Brown (Toward Opaque Typedefs for C++ 1y, v2 2013)により提案が為されています。それが実現すれば、この種の型を定義するのは、より簡単になるでしょう。 

最後の注意点として、これらの型の中で、(型名から変数の内容が)一意に決まらない型タイプがあります。価格のvolatilityと金利のvolatilityは、異なる次元の値と考える必要があります。従って、両者は異なる型として取り扱うべきです。端的に言えば、Volatility型はテンプレート型にすべきでしょう。 

 

 

<ライセンス表示>

QuantLibのソースコードを使う場合は、ライセンス表示とDisclaimerの表示が義務付けられているので、添付します。   ライセンス

目次

Page Top に戻る

// // //