LoginSignup
7
4

More than 5 years have passed since last update.

偏った乱数

Last updated at Posted at 2017-02-13

C++ Builder / String > 文字列の脱落をするクラス」という記事を読んでいて、そういえば C++11 には分布生成器があったということを思い出しました。 C++ に追加された random ヘッダは乱数生成器、生成器アダプタ、分布生成器といった機能を提供しています。 分布生成器は乱数生成器が生成したビット列を元に特定の性質を持つ分布を作り出すものです。

もちろん、その場限りでしか使わないものについてあまり凝った造りにする必要はありませんが、言語が標準的に提供している機能に合わせて作っておくと他のライブラリとも組み合わせやすい可能性があります。 そこで、偏った真偽値を生成する分布生成器を考えてみました。 分布生成器に与えるパラメータは真値 (true) が返ってくる確率を百分率で表した整数です。

分布生成器に求められる要件は仕様 (N3337) の 26.5.1.6 項にあります。 英語に明るくないので完璧に要件に合致している自信はありません。

biased_bool_distribution.h
// -*- mode:c++ -*-
#ifndef HEADER_6fd279ce7d7f5ac14725748253b34d8f
#define HEADER_6fd279ce7d7f5ac14725748253b34d8f
#include <random>
#include <iostream>

class biased_bool_distribution {
public:
  void reset(void);
  typedef bool result_type;
  typedef int param_type;
private:
  std::uniform_int_distribution<int> base;
  param_type bias;
public:
  constexpr static result_type a(void);
  constexpr static result_type b(void);
  param_type param(void) const;
  void param(param_type x);
  constexpr static result_type max(void);
  constexpr static result_type min(void);
  template<class URNG> bool operator()(URNG& g);
  template<class URNG> bool operator()(URNG& g, param_type bias);
  biased_bool_distribution(param_type bias);
};

template<class URNG>
bool biased_bool_distribution::operator()(URNG& g) {
  return base(g) < bias;
}

template<class URNG>
bool biased_bool_distribution::operator()(URNG& g, param_type bias) {
  return base(g) < bias;
}

bool operator==(biased_bool_distribution& x, biased_bool_distribution& y);
bool operator!=(biased_bool_distribution& x, biased_bool_distribution& y);
std::ostream& operator<<(std::ostream& os, biased_bool_distribution& x);
std::istream& operator>>(std::istream& is, biased_bool_distribution& x);
#endif
biased_bool_distribution.cpp
#include "biased_bool_distribution.h"

biased_bool_distribution::biased_bool_distribution(param_type bias)
  : bias(bias), base(0, 99) {
}

void biased_bool_distribution::reset(void) {
  base.reset();
}

constexpr biased_bool_distribution::result_type
biased_bool_distribution::a(void) {
  return 0;
}

constexpr biased_bool_distribution::result_type
biased_bool_distribution::b(void) {
  return 1;
}

constexpr biased_bool_distribution::result_type
biased_bool_distribution::min(void) {
  return 0;
}

constexpr biased_bool_distribution::result_type
biased_bool_distribution::max(void) {
  return 1;
}

biased_bool_distribution::param_type
biased_bool_distribution::param(void) const {
  return bias;
}

void biased_bool_distribution::param(param_type x) {
  bias = x;
}

bool operator==(biased_bool_distribution& x, biased_bool_distribution& y) {
  return x.param()==x.param();
}

bool operator!=(biased_bool_distribution& x, biased_bool_distribution& y) {
  return !(x==y);
}

std::ostream& operator<<(std::ostream& os, biased_bool_distribution& x) {
  os << x.param();
  return os;
}

std::istream& operator>>(std::istream& is, biased_bool_distribution& x) {
  biased_bool_distribution::param_type p=0;
  is >> p;
  x.param(p);
  return is;
}

使い方は他の分布生成器と同じ (になっているはず) です。

sample.cpp
#include <iostream>
#include <random>
#include "biased_bool_distribution.h"

int main() {
  std::random_device seed_gen;
  std::mt19937 engine(seed_gen());

  biased_bool_distribution dist(42);

  for (int i = 0; i < 5; ++i) {
    int result = dist(engine);
    std::cout << result << std::endl;

  }
}
7
4
3

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
7
4