Difference between revisions of "cpp/numeric/random/random device"
From cppreference.com
(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. |
− | + | ||
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) | |
operator= (deleted) |
the assignment operator is deleted (public member function) |
Generation | |
advances the engine's state and returns the generated value (public member function) | |
Characteristics | |
(C++11) |
obtains the entropy estimate for the non-deterministic random number generator (public member function) |
[static] |
gets the smallest possible value in the output range (public static member function) |
[static] |
gets the largest possible value in the output range (public static member function) |
Example
Run this code
#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).
Run this code
//! @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:
Run this code
#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; }