隨機數引擎
linear_congruential_engine 實現線性同餘算法
mersenne_twister_engine 實現梅森纏繞器算法
subtract_with_carry_engine 實現帶進位減(一種延遲斐波那契)算法
以上三個引擎都是類模板,它們第一個模板參數都是UIntType,表示生成數字的類型,且在內部被定義爲result_type成員類型,其他模板參數是特定算法需要的參數。
它們的構造函數類似,以linear_congruential_engine爲例說明:
linear_congruential_engine() : linear_congruential_engine(default_seed) {} (1)
explicit linear_congruential_engine(result_type value); (2)
template <class Sseq>
explicit linear_congruential_engine(Sseq& s); (3)
linear_congruential_engine(const linear_congruential_engine&); (4)(隱式聲明)
構造引擎並初始化狀態。
(1)默認構造函數。以 default_seed 播種引擎。
僅若 Sseq 符合種子序列要求,(3)才參與重載決議。尤其是若 Sseq 可轉換爲 result_type,則從候選函數集中排除該重載。
類 std::seed_seq 滿足種子序列的要求。一個 seed_seq 對象消耗整數值數列,並基於消耗的數據生成請求數量的無符號整數值 i,0<=i < 2^32。產生的值分佈在整個 32 位範圍上,即使消耗的值接近。seed_seq 的構造函數和 generate 函數聲明如下:
seed_seq();
seed_seq(const seed_seq&) = delete;
template <class InputIt>
seed_seq(InputIt begin, InputIt end);
template <class T>
seed_seq(std::initializer_list<T> il);
template <class RandomIt>
void generate(RandomIt begin, RandomIt end);
一個簡單的例子:
#include <random>
#include <cstdint>
#include <iostream>
int main()
{
std::seed_seq seq{1,2,3,4,5};
std::vector<std::uint32_t> seeds(10);
seq.generate(seeds.begin(), seeds.end());
for (std::uint32_t n : seeds) {
std::cout << n << '\n';
}
return 0;
}
回到三個隨機數引擎上,它們還有一些公共的成員函數:
void seed(result_type value = default_seed);
template <class Sseq>
void seed(Sseq& seq);
用新種子值重新初始化隨機數引擎的內部狀態。
result_type operator()();
生成僞隨機數。令引擎狀態前進一個位置。
void discard(unsigned long long z);
令內部狀態前進 z 次。等價於調用 operator() z 次並捨棄結果。
static constexpr result_type min();
返回隨機數引擎潛在生成的最小值。此值等於 0u 。
static constexpr result_type max();
返回隨機數引擎潛在生成的最大值。
此外還有以下非成員函數:
operator==
operator!=
比較兩個僞隨機數引擎的內部狀態
operator<<
operator>>
執行僞隨機數引擎的流輸入和輸出
前者序列化引擎的內部狀態爲一或多個空格分隔的十進制數序列,並插入到流。後者能將十進制數序列還原爲原引擎。
隨機數引擎適配器
template <class Engine, size_t P, size_t R>
class discard_block_engine;
discard_block_engine 忽略基礎引擎所產生的一定量數據。
生成器只從基礎引擎生成的每個 P 大小的塊保留 R 個數,捨棄剩餘的數。
P - 塊大小。必須大於 0 。
R - 每塊用的數字數。必須大於 0 且不大於 P 。
template <class Engine, std::size_t W, class UIntType>
class independent_bits_engine;
class independent_bits_engine 將一個隨機數引擎的輸出適配爲具有特定比特數的數字。
W - 生成數字應有的比特數,其他位填0。必須大於零,且不大於 std::numeric_limits<UIntType>::digits。
UIntType - 生成的隨機數類型。類型必須是無符號整數類型。
std::independent_bits_engine<default_random_engine, 4, unsigned> e;
std::cout << '[' << e.min() << ", " << e.max() << ']' << std::endl; //輸出結果是[0, 15]
template <class Engine, std::size_t K>
class shuffle_order_engine;
shuffle_order_engine 打亂基礎引擎生成的隨機數。
它維護一個大小爲 K 的表,並在請求時隨機地從該表派送被選擇數,將它替換爲基礎引擎生成的數。
非確定隨機數
std::random_device 是生成非確定隨機數的均勻分佈整數隨機數生成器。
std::random_device 可以以實現定義的僞隨機數引擎實現,在某些實現中可能每個 std::random_device 對象生成同一數值序列。
std::random_device 一般作爲其他隨機數引擎的種子使用。
random_device() : random_device(/*implementation-defined*/) {}
explicit random_device(const std::string& token);
標準期待 token 指定產生隨機數字的字節設備,比如 linux 下的 /dev/random 。
random_device(const random_device& ) = delete;
random_device& operator=(const random_device&) = delete;
result_type operator()();
生成均勻分佈的非確定隨機值。
static constexpr result_type min();
返回隨機數引擎潛在生成的最小值。此值等於 0u 。
static constexpr result_type max();
返回隨機數引擎潛在生成的最大值。此值等於 std::numeric_limits<unsigned int>::max() 。
簡單例子:
#include <iostream>
#include <random>
int main()
{
std::uniform_int_distribution<int> d(0, 10);
std::random_device rd1; // 使用 RDRND 或 /dev/urandom
for(int n = 0; n < 10; ++n)
std::cout << d(rd1) << ' ';
std::cout << '\n';
std::random_device rd2("/dev/random"); // Linux 上更慢
for(int n = 0; n < 10; ++n)
std::cout << d(rd2) << ' ';
std::cout << '\n';
}
預定義生成器
minstd_rand0
std::linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647>
由 Lewis、Goodman 及 Miller 發現於 1969,由 Park 與 Miller 於 1988 採納爲“最小標準”
minstd_rand
std::linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647>
較新的“最小標準”,爲 Park、 Miller 及 Stockmeyer 於 1993 推薦
mt19937
std::mersenne_twister_engine<std::uint_fast32_t, ...
32 位梅森纏繞器,由松本與西村發現於 1998
mt19937_64
std::mersenne_twister_engine<std::uint_fast64_t, ...
64 位梅森纏繞器,由松本與西村設計於 2000
ranlux24_base std::subtract_with_carry_engine<std::uint_fast32_t, 24, 10, 24>
ranlux48_base std::subtract_with_carry_engine<std::uint_fast64_t, 48, 5, 12>
ranlux24
std::discard_block_engine<std::ranlux24_base, 223, 23>
24 位 RANLUX 生成器,由 Martin Lüscher 與 Fred James 設計於 1994
ranlux48
std::discard_block_engine<std::ranlux48_base, 389, 11>
48 位 RANLUX 生成器,由 Martin Lüscher 與 Fred James 設計於 1994
knuth_b
std::shuffle_order_engine<std::minstd_rand0, 256>
default_random_engine
實現定義
一般來說像下面這樣用:
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::default_random_engine gen(rd());
for(int i=0; i<10; ++i)
std::cout << gen() << ' ';
return 0;
}
用於產生滿足特定分佈數字的類/類模板/函數模板
generate_canonical
template <class RealType, size_t bits, class Generator>
RealType generate_canonical(Generator& g);
生成範圍 [0, 1) 中的隨機浮點值。
RealType - 浮點類型。
bits - 精度,如果該值大於RealType的精度,將使用 numeric_limits<RealType>::digits 。
簡單例子:
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
for(int n = 0; n < 10; ++n) {
std::cout << std::generate_canonical<double, 10>(gen) << ' ';
}
}
均勻分佈
uniform_int_distribution
產生在一個範圍上均勻分佈的整數值。(類模板)
uniform_real_distribution
產生在一個範圍上均勻分佈的實數值。(類模板)
伯努利分佈
bernoulli_distribution
產生伯努利分佈上的 bool 值。(類)
binomial_distribution
產生二項分佈上的整數值。(類模板)
negative_binomial_distribution
產生負二項分佈上的整數值。(類模板)
geometric_distribution
產生幾何分佈上的整數值。(類模板)
泊松分佈
poisson_distribution
產生泊松分佈上的整數值。(類模板)
exponential_distribution
產生指數分佈上的實數值。(類模板)
gamma_distribution
產生 Γ 分佈上的實數值(類模板)
weibull_distribution
產生威布爾分佈上的實數值。(類模板)
extreme_value_distribution
產生極值分佈上的實數值。(類模板)
正態分佈
normal_distribution
產生標準正態(高斯)分佈上的實數值。(類模板)
lognormal_distribution
產生對數正態分佈上的實數值。(類模板)
chi_squared_distribution
產生 χ2 分佈上上的實數值。(類模板)
cauchy_distribution
產生柯西分佈上的實數值。(類模板)
fisher_f_distribution
產生費舍爾 F 分佈上的實數值。(類模板)
student_t_distribution
產生學生 t 分佈上的實數值。(類模板)
採樣分佈
discrete_distribution
產生離散分佈上的隨機整數。(類模板)
piecewise_constant_distribution
產生分佈在常子區間上的實數值。(類模板)
piecewise_linear_distribution
產生分佈在定義的子區間上的實數值。(類模板)
以上的類或類模板使用方式都是類似的,構造函數根據參數生成概率分佈函數,使用operator()()根據關聯的概率分佈函數生成隨機數。
他們主要有以下常用成員:
成員類型result_type,operator()()的返回值。
void reset();
重置分佈對象的內部狀態
template <class Generator>
result_type operator()(Generator& g);
根據關聯的概率分佈函數生成隨機數。由調用 g.operator() 獲得熵。
result_type min() const;
返回分佈潛在生成的最小值。
result_type max() const;
返回分佈潛在生成的最大值。
看一個正態分佈的例子:
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
int main()
{
std::random_device rd{};
std::mt19937 gen{rd()};
// 值最可能接近平均
// 標準差影響生成的值距離平均數的分散
std::normal_distribution<> d{5,2};
std::map<int, int> hist;
for(int n=0; n<50000; ++n)
{
++hist[std::round(d(gen))];
}
for(auto &p : hist)
{
std::cout << std::setw(2)
<< p.first << ' ' << std::string(p.second/200, '*') << '\n';
}
return 0;
}
輸出是:
-4
-3
-2
-1
0 **
1 *******
2 ***************
3 ******************************
4 *******************************************
5 *************************************************
6 *******************************************
7 ******************************
8 ****************
9 ******
10 **
11
12
13
14
參考 cppreference.com cplusplus.com