乱数
乱数操作についてまとめます。
Examples:
基本的な乱数を生成する例です。
// 乱数を使うには std.random をimportして使います。 // 最も簡単な乱数を得る方法は、一様乱数を生成する uniform を使う方法です。 import std.random : uniform; // 0.0以上、1.0未満の乱数を生成します。 auto p = uniform(0.0, 1.0); assert(0.0 <= p && p < 1.0); // 結果の型は引数から推論されるため、floatが必要な場合は引数をfloat型にします。 auto fp = uniform(0.0f, 1.0f); assert(0.0f <= fp && fp < 1.0f); // 半開区間ではなく閉区間(両端を含む)で乱数の値域を設定する場合、uniformのテンプレートパラメーターを使います。 auto q = uniform!"[]"(-1.0, 1.0); assert(-1.0 <= q && q <= 1.0); // 0以上1未満の乱数を生成する場合は uniform01 という関数が使えます。 import std.random : uniform01; auto r = uniform01(); auto fr = uniform01!float(); assert(0.0 <= r && r < 1.0); assert(0.0 <= fr && fr < 1.0);
Examples:
配列を乱数で初期化する例です。
import std.random : uniform; import std.algorithm.iteration : each; // 任意の長さを持つ配列に対して、std.algorithmのeachを使うことで全要素を参照することができます。 auto data = new double[](1000); data.each!((ref x) { x = uniform!"[]"(-10.0, 10.0); }); foreach (x; data) { assert(-10.0 <= x && x <= 10.0); }
Examples:
シミュレーション用途など、再現可能な乱数を作るためにシードを指定する例です。
実行時に毎回異なるシードを使う場合は、 unpredictableSeed を使用します。
// メルセンヌツイスター法による Random のほかに Xorshift の乱数生成器も使うことができます。 import std.random : Random, Xorshift, uniform; Random rndGen1; Xorshift rndGen2; // シードを設定することで何度やっても同じ値が取得可能になります。 // 実験などではこのrndGenをベースに乱数を作ることになります。 rndGen1.seed = 1000; rndGen2.seed = 1000; assert(rndGen1.front == 2807145907u); assert(rndGen2.front == 2096656543u); // 乱数生成器は無限Rangeであるため、次の要素を取り出す前にpopFrontします。 rndGen2.popFront(); // uniformなどの乱数を取得するための関数は、最後の引数に乱数生成器を指定することができます。 // これらは呼び出すたびに内部的にpopFrontされるため、取得の度に新しい乱数が取得できます。 auto p = uniform(-1.0f, 1.0f, rndGen1); auto q = uniform(-1.0f, 1.0f, rndGen1); import std.math : isClose; assert(p.isClose(0.307179)); assert(q.isClose(-0.588957));
Examples:
標準正規分布に基づく乱数を生成する例です。
std.mathspecial にある normalDistributionInverse を使うことで確率変数から逆変換できます。
normalDistributionInverse : https://dlang.org/phobos/std_mathspecial.html#normalDistributionInverse
import std.random : uniform; import std.mathspecial : normalDistributionInverse; // 0と1は-infとinfに振り切れてしまうため、値域を指定することで除外できます。 auto p = normalDistributionInverse(uniform!"()"(0.0, 1.0)); assert(-double.infinity < p && p < double.infinity);