LoginSignup
15

More than 5 years have passed since last update.

お手軽 乱数実装【C++11】

Last updated at Posted at 2018-12-01

こちらはC++ Advent Calendar 2018 2日目の記事です。

1日目: C++ で async/await をする
3日目: C++ ライフをよりハッピーにするための 14の小ネタ

C++の乱数は"初見殺し"なので……

皆さん、C++の乱数ライブラリである<random>は使用していますか?
まさか Csrandrandを使用している人はいませんよね……?

C++の扱いに手馴れている人にとっては、<random>ライブラリは手ごわい相手ではないでしょう。
しかし、初心者にとっては難攻不落ではないかと思います。

そこで、以下の便利ソースコードを使用すると
簡単に、そして楽に乱数ライブラリが扱えるようになります。

ちなみにrandomライブラリの説明は2年前にいなむ先生が記事を出しているのでそちらをご覧ください。
C++の乱数ライブラリが使いにくい話

便利ソースコード

Random.hpp
#pragma once
#include <random>
#include <cstdint>

class Rand {
private:
    //32ビット版メルセンヌ・ツイスタ
    std::mt19937 mt;
    //非決定論的な乱数
    std::random_device rd;

public:
    //コンストラクタ(初期化)
    Rand() { mt.seed(rd()); }

    //初期値
    void seed() {
        mt.seed(rd());
    }
    void seed(const std::uint_fast32_t seed_) {
        mt.seed(seed_);
    }

    //通常の乱数
    std::uint_fast32_t operator()() {
        return mt();
    }
    //0~最大値-1 (余りの範囲の一様分布乱数)
    std::int_fast32_t operator()(const std::int_fast32_t max_) {
        std::uniform_int_distribution<> uid(0, ((max_ > 0) ? (std::int_fast32_t)max_ - 1 : 0));
        return uid(mt);
    }
    //最小値~最大値
    std::int_fast32_t operator()(const std::int_fast32_t min_, const std::int_fast32_t max_) {
        std::uniform_int_distribution<> uid((min_ <= max_) ? min_ : max_, (min_ <= max_) ? max_ : min_);
        return uid(mt);
    }
    //確率
    bool randBool(const double probability_) {
        std::bernoulli_distribution uid(probability_);
        return uid(mt);
    }
    bool randBool() {
        std::uniform_int_distribution<> uid(0, 1);
        return ((uid(mt)) ? true : false);
    }
};
static thread_local Rand rnd;

C++の<random>ライブラリを初心者でも
扱いやすくしたクラスです。

C言語のrandよりも簡単に扱えます。

使い方

通常の乱数を生成

Source1.cpp
#include "Random.hpp"
#include <iostream>

int main() {

    for (size_t i = 0; i < 10; ++i) {
        std::cout << rnd() << std::endl;
    }

    return 0;
}
出力例
1177009351
53076842
3741984662
4148031424
3743658273
3492815540
3731663521
2691610594
1148602447
3200622187

rnd()で乱数生成します。

範囲指定(余りの範囲の一様分布乱数)

Source2.cpp
#include "Random.hpp"
#include <iostream>

int main() {

    for (size_t i = 0; i < 10; ++i) {
        std::cout << rnd(10) << std::endl;
    }

    return 0;
}
0
1
3
9
5
7
1
5
5
7

rnd(n)通常乱数をnで割った余りの範囲の一様分布乱数を生成します。

範囲指定

Source3.cpp
#include "Random.hpp"
#include <iostream>

int main() {

    for (size_t i = 0; i < 10; ++i) {
        std::cout << rnd(10, 20) << std::endl;
    }

    return 0;
}
10
19
18
10
19
14
20
11
13
13

rnd(n1 , n2)n1からn2の範囲の乱数を生成します。

確率

Source4.cpp
#include "Random.hpp"
#include <iostream>

int main() {

    for (size_t i = 0; i < 10; ++i) {
        std::cout << (rnd.randBool(0.7) ? "あたり!" : "はずれ") << std::endl;
    }

    return 0;
}
はずれ
あたり!
あたり!
あたり!
あたり!
はずれ
あたり!
あたり!
はずれ
あたり!

乱数で確率を使用します。

初期値指定

Source5.cpp
#include "Random.hpp"
#include <iostream>

int main() {

    for (size_t i = 0; i < 10; ++i) {
        rnd.seed(1000);
        std::cout << rnd() << std::endl;
    }

    return 0;
}
2807145907
2807145907
2807145907
2807145907
2807145907
2807145907
2807145907
2807145907
2807145907
2807145907

rnd.seed(n)で初期値が指定できます。
ちなみにrnd.seed()と値を入れない場合は、
ランダムな値を初期値として設定します。

ソースコードのライセンス

These codes are licensed under CC0.
CC0

ソースコードは自由に使用してください。

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
15