randsub.NET.zip (VB.NET)
比較的高速な減算法を用いて一様乱数を得る方法を紹介します。Ran3というクラス名にしてありますが、
NUMERICAL RECIPES in C (日本語版)
William H. Press, Saul A. Teukolsky, William T. Vetterling, Brian P. Flannery
技術評論社
ISBN4-87408-560-1
に掲載されている関数を移植した、という立場で、名称を踏襲しています。
randsub.NET.zip (VB.NET)
比較的高速な減算法を用いて一様乱数を得る方法を紹介します。Ran3というクラス名にしてありますが、
NUMERICAL RECIPES in C (日本語版)
William H. Press, Saul A. Teukolsky, William T. Vetterling, Brian P. Flannery
技術評論社
ISBN4-87408-560-1
に掲載されている関数を移植した、という立場で、名称を踏襲しています。
しかし、乱数を得る組み込み関数のアルゴリズムとして多くのシステムで合同法が採用されている中で、.Net Frameworkの場合は減算法を用いています。実のところ、System.Randomクラスの内部的な31bit整数の乱数生成の実装も、NUMERICAL RECIPESの移植であることはほぼ間違いありません。
Microsoft社のシェアードソースCLIをダウンロード(1.0はこちら、2.0はこちら)することによりソースコードを入手でき、内容を詳細に検討できますが、System.Randomクラスでは、Double型浮動小数点数で乱数を得るNextDouble関数(内部的にはSample関数)も、Double型の52bitの仮数部のうち高々31bitしか用いていません。Sample関数をオーバーライドする派生クラスを作った場合、その影響を受ける関数が.Net Frameworkのバージョン間で違います。さらに、8bit整数の乱数列を得るNextBytesメソッドでは、.Net Frameworkの1.0では31bitの整数の上位bitを、2.0では下位bitを用いる(一般的に擬似乱数の下位bitを使用することは統計的に推奨されません。)など、.Net Frameworkのバージョン間で一貫性がありません。
このようなSystem.Randomクラスのバージョン間差異や統計的な根拠の不明点(こちらにメモがあります。)を解消するため、ここでは、System.Randomクラスと同等の関数やメソッドを備え、かつ、一貫性、整合性がより高い実装を行うこととしました。
31bitの基本となる整数の乱数を得るNextRaw関数、これに基づいて、仮数部の上位31bitのみを用いてDouble型浮動小数点数の乱数を得るNextDoubleRaw関数、さらに、8bit整数の乱数列をByte型配列に格納するNextBytesRawメソッドを備えています。これらの名前にはすべて「Raw」の文字が入っていますが、次に述べるSample関数より上流側に位置して、Sample関数の影響を受けない「生」の乱数を提供することを意味します。
NextRaw関数を2回呼び出して31bit整数の乱数を2つ得て、それぞれの上位26bitを取り出し、Double型浮動小数点数の仮数部52bitに格納し、[0,1)の範囲の浮動小数点数を得るSample関数を備えています。これは、Protected Overridableな関数で、派生クラスでOverrideすることができます。[0,1)の範囲は守りつつ分布の異なる乱数を生成すれば、次に述べる関数やメソッドで得られる乱数の分布も連動して変更されます。
Sample関数が返す結果に基づき、Double型浮動小数点数の乱数を得るNextDouble関数、Integer型整数の乱数を得るNext関数(範囲を指定できるオーバーロードあり)、さらに、8bit整数の乱数列をByte型配列に格納するNextBytesメソッドがあります。
減算法は、合同法に比べて研究対象としてあまりよく取り組まれていない様子で、実のところ、ここで紹介しているクラスについても、周期すら不明です。したがって、このクラスを応用される方、特に、結果の統計的振る舞いを定量的に議論する必要がある方は、まず、このクラスで生成される乱数自体の統計をよく検証する必要があります。
31bitの整数型の乱数を得る方法は、合同法のアルゴリズムも紹介していますので、ここで示したソースコードのInitializeメソッドとNextRawメソッドの実装を差し替えて用いることも、一つお奨めの方法です。