3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自作の乱数生成器を乱数分布ライブラリ(std::uniform_int_distribution)と組み合わせる

Last updated at Posted at 2024-11-13

概要

乱数生成器をカスタム実装し、乱数分布ライブラリ std::uniform_int_distributionと組み合わせて使用する方法を実践的に説明する。

ソースコードについては、https://github.com/youpong/RandomEngine を利用できる。

必要条件

プログラムは、標準規格 C++20 に準拠している。そのため、新しいバージョンの C++ コンパイラーと C++ 標準ライブラリの実装が必要になる。

テスト環境

以下の環境でテストしている。

  • macOS 15.2
    • Xcode 16.2 (バンドルされる Apple Clang 16.0.0 を使用)
  • Ubuntu 24.04.1 LTS
    • GCC 13.3.0
    • Clang 18.1.3

手順

ここでは、次のような流れで開発する。

  1. C++標準ライブラリの乱数生成器 std::default_ramdom_engine と乱数分布 std::uniform_int_distribution を組み合わせたプログラムを作成する。
  2. 乱数生成器 RandomEngine をカスタム実装する。
  3. 乱数生成器をカスタム実装の RandomEngine と置き換える。

C++ コンパイラのフラグを設定する

以下の内容の Makefile を用意する。プログラムが C++20 規格に準拠していることと、
コンパイル時のワーニングをなるべく多くだすようにしている。

CXXFLAGS = -std=c++20 -Wall -Wextra --pedantic-errors

C++標準ライブラリの乱数生成器と乱数分布を組み合わせる

ファイル名 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 && make run

実行結果は以下の様になる。 
実行結果は環境によって異なるだろう。

2 6 5 1 3 1 1 3 3 3 

乱数生成器をカスタム実装する

乱数生成クラスは、以下のクラスメソッドを実装する必要がある。

  • min() - 生成する乱数の最小値を返す
  • max() - 生成する乱数の最大値を返す

以下のインスタンスメソッドを実装する必要がある。

  • operator() - 乱数を生成する

以下の型エイリアスを実装する必要がある

  • result_type - 生成する乱数の型(非負1

具体的な実装例は以下の様になる。

class RandomEngine {
public:
    using result_type = unsigned int;

private:
    // params from cc65 compiler
    unsigned int a = 16'843'009;
    unsigned int x;
    unsigned int c = 826'366'247;
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 std::numeric_limits<unsigned int>::max();
    }
};

カスタム実装した乱数生成器に置き換える

#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 && make run

実行結果は以下の様になる。

6 5 2 1 6 5 2 1 6 5 

以上です。

参考文献

  1. 江添亮. 江添亮のC++入門. ドワンゴ, 2019, Kindle版, 39.3 乱数分布.
  1. LLVM のサブプロジェクトlibc++ による C++ 標準ライブラリの実装では、 std::uniform_int_distribution のオブジェクトが引き受ける乱数生成器について、非負の乱数を生成することを求めている。
    詳しくは、libc++ プロジェクトの include/__random/is_valid.h で定義されている __libcpp_random_is_valid_urng を参照のこと。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?