擬似乱数の生成アルゴリズムにはいくつか種類がありますが、Randomクラスを継承して独自に疑似乱数を実装することもできます。 Randomクラスを継承して疑似乱数生成アルゴリズムを実装する際に最低限必要となるのは、Sampleメソッドをオーバーライドし、0.0以上1.0未満の乱数を返すように実装することです。
以下の例では、線形合同法を実装したLCGRandomクラスを作成し、Randomクラスが生成する乱数との比較を行っています。 なお、この実装は一つの例として挙げたもので、生成される乱数の周期や分散については考慮していません。 実際に使用する場合は注意してください。
Randomクラスを継承して線形合同法による擬似乱数を実装する
using System;
// 線形合同法による疑似乱数の生成を実装したクラス
class LCGRandom : Random {
private long x;
private const long a = 1140671485;
private const long c = 12820163;
public LCGRandom()
: this(Environment.TickCount) // Environment.TickCountの値をデフォルトのシード値として使用する
{
}
public LCGRandom(int seed)
{
x = seed;
}
protected override double Sample()
{
x = unchecked(a * x + c) & long.MaxValue;
return (double)x / long.MaxValue;
}
}
class Sample {
static void Main()
{
var rand = new Random(0);
var lcg = new LCGRandom(0);
const string format = "{0,-6} {1,-6}";
Console.WriteLine(
format,
nameof(rand),
nameof(lcg)
);
for (var i = 0; i < 15; i++) {
Console.WriteLine(
format,
rand.Next(0, 100),
lcg.Next(0, 100)
);
}
}
}
実行結果
rand lcg 72 0 81 0 76 97 55 2 20 65 55 93 90 23 44 65 97 44 27 61 29 37 46 18 63 78 46 82 98 28
この例ではオーバーフロー時に例外のスローを抑止する目的でunchecked
ステートメント、および/removeintchecks+
コンパイルオプションを使用しています。 詳しくは整数型のオーバーフローとチェックを参照してください。
このように、Sampleメソッドをオーバーライドすることで独自の乱数生成を行うことができます。 場合によっては、Sampleメソッドを適切に実装することでメソッドの戻り値の範囲が閉区間となるようにすることもできます。
なお、Randomクラスを継承する場合、引数をとらないNextメソッドなどSample以外のメソッドもオーバーライドしないと動作が変わらないメソッドがあります。 詳しくはSampleメソッドのリファレンスを参照してください。