Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/numeric/random/random device"

From cppreference.com
< cpp‎ | numeric‎ | random
(port workaround code for mingw libstdc++ from cpprefjp(CC-BY, https://cpprefjp.github.io/reference/random/random_device.html))
m (fix syntax)
Line 73: Line 73:
 
==== MinGW GCC(libstdc++) ====
 
==== MinGW GCC(libstdc++) ====
  
In MinGW GCC(libstdc++), {{tt|std::random_device}} is implemented by {{tt|std::mt19937}}
+
In MinGW GCC(libstdc++), {{tt|std::random_device}} is implemented by {{tt|std::mt19937}} that is non-deterministic.
that is non-deterministic.
+
  
 
As a workaround, you can use CryptGenRandom (Win32API).
 
As a workaround, you can use CryptGenRandom (Win32API).

Revision as of 20:44, 21 April 2018

 
 
 
 
 
Defined in header <random>
class random_device;
(since C++11)

std::random_device is a uniformly-distributed integer random number generator that produces non-deterministic random numbers.

std::random_device may be implemented in terms of an implementation-defined pseudo-random number engine if a non-deterministic source (e.g. a hardware device) is not available to the implementation. In this case each std::random_device object may generate the same number sequence.

Contents

Member types

Member type Definition
result_type unsigned int

Member functions

Construction
constructs the engine
(public member function) [edit]
operator=
(deleted)
the assignment operator is deleted
(public member function)
Generation
advances the engine's state and returns the generated value
(public member function) [edit]
Characteristics
(C++11)
obtains the entropy estimate for the non-deterministic random number generator
(public member function) [edit]
[static]
gets the smallest possible value in the output range
(public static member function) [edit]
[static]
gets the largest possible value in the output range
(public static member function) [edit]

Example

#include <iostream>
#include <string>
#include <map>
#include <random>
 
int main()
{
    std::random_device rd;
    std::map<int, int> hist;
    std::uniform_int_distribution<int> dist(0, 9);
    for (int n = 0; n < 20000; ++n) {
        ++hist[dist(rd)]; // note: demo only: the performance of many 
                          // implementations of random_device degrades sharply
                          // once the entropy pool is exhausted. For practical use
                          // random_device is generally only used to seed 
                          // a PRNG such as mt19937
    }
    for (auto p : hist) {
        std::cout << p.first << " : " << std::string(p.second/100, '*') << '\n';
    }
}

Possible output:

0 : ********************
1 : *******************
2 : ********************
3 : ********************
4 : ********************
5 : *******************
6 : ********************
7 : ********************
8 : *******************
9 : ********************


Note

MinGW GCC(libstdc++)

In MinGW GCC(libstdc++), std::random_device is implemented by std::mt19937 that is non-deterministic.

As a workaround, you can use CryptGenRandom (Win32API).

//! @file random_device.hpp
#pragma once
 
#include <random>
 
#if defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
 
#include <system_error>
#include <limits>
#include <string>
#include <Windows.h>
#include <wincrypt.h>
 
namespace workaround_mingw_gcc {
class random_device {
private:
  class crypt_context {
  private:
    HCRYPTPROV prov_;
  public:
    crypt_context(DWORD prov_type, LPCTSTR container = nullptr, LPCTSTR provider = nullptr, DWORD flags = 0) {
      const auto success = ::CryptAcquireContext(&this->prov_, container, provider, prov_type, flags);
      if (!success) {
        throw std::system_error(
          std::error_code(::GetLastError(), std::system_category()),
          "CryptAcquireContext:(" + std::to_string(success) + ')'
        );
      }
    }
    crypt_context(const crypt_context&) = delete;
    void operator=(const crypt_context&) = delete;
    ~crypt_context() noexcept {
      ::CryptReleaseContext(this->prov_, 0);
    }
    //HCRYPTPROV& get() noexcept { return this->prov_; }
    const HCRYPTPROV& get() const noexcept { return this->prov_; }
  };
  crypt_context prov_;
 
public:
  using result_type = unsigned int;
  explicit random_device(const std::string& /*token*/ = "workaround_mingw_gcc ")
  : prov_(PROV_RSA_FULL)
  {}
  random_device(const random_device&) = delete;
  void operator=(const random_device&) = delete;
  //~random_device() = default;
  double entropy() const noexcept { return 0.0; }
  result_type operator()() {
    result_type re;
    const auto success = ::CryptGenRandom(this->prov_.get(), sizeof(re), reinterpret_cast<BYTE*>(&re));
    if (!success) {
      throw std::system_error(
        std::error_code(::GetLastError(), std::system_category()),
        "CryptGenRandom:(" + std::to_string(success) + ')'
      );
    }
    return re;
  }
  static constexpr result_type min() { return std::numeric_limits<result_type>::min(); }
  static constexpr result_type max() { return std::numeric_limits<result_type>::max(); }
};
} // namespace workaround_mingw_gcc
 
namespace cppreference {
using workaround_mingw_gcc::random_device;
}
 
#else //defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
 
namespace cppreference {
using std::random_device;
}
 
#endif //defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)

Usage:

#include "random_device.hpp"
#include <iostream>
#include <array>
#include <functional>
#include <algorithm>
using seed_v_t = std::array<cppreference::random_device::result_type, sizeof(std::mt19937)/sizeof(cppreference::random_device::result_type)>;
seed_v_t create_seed_v()
{
  cppreference::random_device rnd;
  seed_v_t sed_v;
  std::generate(sed_v.begin(), sed_v.end(), std::ref(rnd));
  return sed_v;
}
std::mt19937 create_random_engine()
{
  const auto sed_v = create_seed_v();
  std::seed_seq seq(sed_v.begin(), sed_v.end());
  return std::mt19937(seq);
}
std::mt19937& random_engine() {
  static thread_local std::mt19937 engine = create_random_engine();
  return engine;
}
int main()
{
  std::mt19937& engine = random_engine();
  std::uniform_int_distribution<int> dist(1, 32);
  for(int i = 0; i < 10; ++i) std::cout << dist(engine) << std::endl;
}