C++
Random
C++11
乱数
確率
C++Day 2

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

こちらは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

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