C++ の std::uniform_int_distribution は、乱数エンジンが生成する値より大きな整数を生成できる

タイトル通り。

https://wandbox.org/permlink/IQJOgUKdZ2k2KmMf

#include <utility>
#include <random>

struct my_random_generator {
    typedef std::mt19937::result_type result_type;
    static constexpr result_type min() noexcept { return 0; }
    static constexpr result_type max() noexcept { return 1; }

    template<class... Args>
    explicit my_random_generator(Args&&... args)
        : orig_(std::forward<Args>(args)...) {}

    template<class... Args>
    void seed(Args&&... args) {
        this->orig_.seed(std::forward<Args>(args)...);
    }

    result_type operator()() {
        return this->orig_() % 2;
    }

    void discard(unsigned long long z) {
        this->orig_.discard(z);
    }

 private:
    std::mt19937 orig_;
};

#include <iostream>

int main() {
    my_random_generator gen;
    std::uniform_int_distribution<> dist(1, 6);

    for (int i = 0; i < 10; ++i) {
        std::cout << dist(gen) << std::endl;
    }
}
1
6
4
5
6
3
1
6
4
2

上記コードで用いられている乱数生成エンジンは 0 か 1 かのみを返すエンジンだが、そのような極端なエンジンであっても、 std::uniform_int_distribution を用いれば、きちんと整数乱数を生成できる。


試しに乱数を生成するたびにログを出してみる:

https://wandbox.org/permlink/m2PUQEN3WnrQPvCI

#include <utility>
#include <random>
#include <iostream>

struct my_random_generator {
    typedef std::mt19937::result_type result_type;
    static constexpr result_type min() noexcept { return 0; }
    static constexpr result_type max() noexcept { return 1; }

    template<class... Args>
    explicit my_random_generator(Args&&... args)
        : orig_(std::forward<Args>(args)...) {}

    template<class... Args>
    void seed(Args&&... args) {
        this->orig_.seed(std::forward<Args>(args)...);
    }

    result_type operator()() {
        std::cout << "random number generated.\n";
        return this->orig_() % 2;
    }

    void discard(unsigned long long z) {
        this->orig_.discard(z);
    }

 private:
    std::mt19937 orig_;
};

int main() {
    my_random_generator gen;
    std::uniform_int_distribution<> dist(1, 6);

    for (int i = 0; i < 10; ++i) {
        std::cout << dist(gen) << std::endl;
    }
}
random number generated.
random number generated.
random number generated.
1
random number generated.
random number generated.
random number generated.
6
random number generated.
random number generated.
random number generated.
random number generated.
random number generated.
4
random number generated.
random number generated.
random number generated.
5
random number generated.
random number generated.
random number generated.
6
random number generated.
random number generated.
random number generated.
3
random number generated.
random number generated.
random number generated.
random number generated.
random number generated.
random number generated.
random number generated.
1
random number generated.
random number generated.
random number generated.
6
random number generated.
random number generated.
random number generated.
4
random number generated.
random number generated.
random number generated.
2

一回の整数乱数生成に際して複数回乱数エンジンが呼び出されていることが分かる。


参考:

cpplover.blogspot.com