預設亂數生成器是 std::default_random_engine 型別別名定義的隨機無符號整數的通用源。這個別名表示實現是被定義的,選擇的模板型別引數需要能夠為使用者提供他們滿意的序列。下面是一種生成 default_random_engine 型別的疊代器的簡單方式:
std::default_random_engine rngl; // Create random number generator with default seed
這裡呼叫預設的建構函式,因此會用預設種子來設定初始狀態。在不同的時刻執行從 rng1 產生的亂數字序列總是相同的,因為種子保持不變。當然,也能自己提供種子:
std::default_random_engine rng2 {10}; // Create rng with 10 as seed
這裡以 10 為種子生成了 rng2,因此從這個生成器中得到的隨機序列和從 rng1 得到的是不同的,但仍然是固定的。如果想在每次執行程式碼時都得到不同的序列,需要提供非確定性的種子:
std::random_device rd; // Non-determinstic seed source
std::default_random_engine rng3 {rd()}; // Create random number generator
種子值是通過 random_device 型別的函數物件 rd 獲得的。每一個 rd() 呼叫都會返回不同的值,而且如果我們實現的 random_devic 是非確定性的,程式每次執行連續呼叫 rd() 都會產生不同的序列。
另一個選擇是,提供一個 seed_seq 物件作為 default_random_engine 建構函式的引數:
std::seed_seq sd_seq {2, 4, 6, 8};
std::default_random_engine rng4 {sd_seq}; // Same random number sequence each time
std::random_device rd; // Non-determinstic seed source
std::default_random_engine rng5 {std::seed_seq{rd(), rd(), rd()}};
這裡第一次用從固定的初始種子生成的 seed_seq 物件生成 rng4 生成器;每次執行這段程式碼,從 rng4 得到的序列都是相同的。 rng5 是從 seed_seq 構造的,seed_seq 擁有 random_device 函數物件產生的值,因此我們永遠不知道會產生什麼序列(每次都是一個驚喜)。我們現在正處於一個創造和使用分布物件的位置,並開始一些嚴肅的隨機活動。
建立分布物件
正如之前所說的,為了產生分布內的值,表示分佈的函數物件需要一個亂數生成器物件作為引數。每次執行分布物件,都會返回一個在它所表示的分布之內的亂數,這個亂數是從亂數生成器所獲得的值生成的。在分布返回的第一個值後面的連續值都依賴前面的值。建立一個分布物件需要一系列依賴分布型別的引數值。例如,均勻分布需要生成值的上下邊界,而正態分布需要的是平均值和標準差。儘管不同型別的分布之間有本質上的不同,但它們還是有很多共同之處。所有的分布物件都有下面這些公共成員:
-
result_type 是在類中為生成值的型別定義的型別別名。
-
min() 是一個返回分布物件可生成的最小值的成員函數。
-
max() 是一個返回分布物件可生成的最大值的成員函數。
-
reset() 是一個可以將分布物件重置為它的原始狀態的成員函數,這樣下次返回的值就不會依賴前一個值。這是否會發生取決於我們的實現。分布返回的值是獨立的,reset() 不會做任何事情。
-
param_type 是定義在類中的一個結構體的型別別名。不同的分布需要不同的引數值,可能還需要是不同的型別,這些值會被儲存到一個用來指定分布的 param_type 類結構體中。
-
param() 是一個接受一個 param_type 型別的引數的成員函數,它會將分布物件的引數重置為新的值。
-
param() 的無參過載版本,它會返回分布物件所包含的 param_type 物件。
-
預設建構函式對於定義分布的引數有預設值。
-
一個建構函式,接受 param_type 型別的引數來定義分布。
後面會展示這些成員函數如何用於某些型別的分布。為了可以將分布物件的內部狀態傳送到流,或為了從流中讀回狀態,對流的插入和提取運算子、< 和 >>,為分布型別進行了過載。這樣就提供了恢復程式的上一次執行中分布的狀態的能力。