概要
独自のアルゴリズムで乱数生成器を作成し、標準の乱数分布と組み合わせて使用する方法を実践的に説明する。
環境
macOS 15.1
Xcode 16.1
C++ コンパイラのフラグを設定する
以下の内容の Makefile を用意する。
CXXFLAGS = -g -std=c++20 -O0 -Wall -Wextra --pedantic-errors
乱数分布ライブラリで乱数を望みの範囲に加工する
ファイル名 main.cpp で以下の内容を保存する。
#include <iostream>
#include <random>
int main() {
std::uniform_int_distribution<int> d(1, 6);
std::default_random_engine e;
for (auto i = 0; i != 10; ++i) {
std::cout << d(e) << " ";
}
}
実行する
$ make main && ./main
実行結果は以下の様になる。
実行結果は環境によって異なるだろう。
2 6 5 1 3 1 1 3 3 3
乱数生成器を自作する
先のファイルの先頭に以下の内容を追加する。
RandomEngine
は、線形合同法(Linear Congruential generator)を実装している。
class RandomEngine
{
public:
using result_type = unsigned int;
private:
unsigned int a = 3;
unsigned int x;
unsigned int c = 5;
// int m;
public:
RandomEngine(unsigned int seed = 0) : x(seed) {}
result_type operator()() {
x = a * x + c;
return x;
}
static constexpr result_type min() {
return 0;
}
static constexpr result_type max() {
return UINT_MAX;
}
};
ここで RandomEngine::result_type
が非負で定義されていることに注意。
LLVM のサブプロジェクトlibc++ による C++ 標準ライブラリの実装では、 std::uniform_int_distribution のオブジェクトが引き受ける乱数生成器について、非負の乱数を生成することを求めている。
詳しくは、libc++ プロジェクトの include/__random/is_valid.h で定義されている __libcpp_random_is_valid_urng
を参照のこと。
先のプログラムにて自作した乱数生成器に置き換える
#include <iostream>
#include <random>
int main() {
std::uniform_int_distribution<int> d(1, 6);
RandomEngine e; // <- 置き換えた
for (auto i = 0; i != 10; ++i) {
std::cout << d(e) << " ";
}
}
実行する
$ make main && ./main
実行結果は以下の様になる。
実行結果は環境によって異なるだろう。
6 5 2 1 6 5 2 1 6 5