0
0

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

手順

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

以下の内容の Makefile を用意する。以下の CXXFLAGS の値は clang++ と g++ で共通して
利用できる。

CXXFLAGS = -std=c++20 -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 && make run

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

2 6 5 1 3 1 1 3 3 3 

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

先のファイルの先頭に乱数生成器のカスタム実装クラス RandomEngine を加える。

// Implemented by 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 && make run

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

6 5 2 1 6 5 2 1 6 5 
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?