C c 11中的隨機數 random

2021-08-17 04:38:13 字數 3989 閱讀 7086

在 c++ 程式中,在新標準出現之前,c 和 c++ 都依賴乙個簡單的 c 庫函式rand來生成隨機數,但是,這個函式生成的是均勻分布的偽隨機數,每個隨機數的範圍在 0 和乙個系統相關的最大值(至少為 32767)之間。

rand函式有一些問題:即使不是大多數,也有很多程式需要不通範圍的隨機數。一些應用需要隨機浮點數。一些程式需要非均勻分布的隨機數。而在編寫程式為了解決這些通常會轉換rand生成的隨機數的範圍、型別或者是分布時,常常會引入非隨機性。

在 c++ 11 標準中,定義在標頭檔案random中的隨機數庫通過一組協作的類來解決這些問題,主要用到的是兩個類:

其中,乙個引擎類可以生成unsigned隨機數列,乙個分布使用乙個引擎類生成指定型別的,在給定範圍內的,服從指定概率分布的隨機數。

隨機數引擎是函式物件類,他們定義了乙個呼叫運算子,該運算子不接受引數並返回乙個隨機的unsigned整數。我們可以通過呼叫乙個隨機數引擎物件來生成原始隨機數。

default_random_engine e;    // 生成隨機無符號數

for(size_t i=0; i<10; i++)

// e() 「呼叫」物件來生成下乙個隨機數

cout << e()

《在上面這幾行的**中,定義了乙個名為edefault_random_engine的物件。在 for 迴圈內,我們呼叫物件 e 來獲得下乙個隨機數。

為了得到乙個在指定範圍內的數,我們一用乙個分布型別的物件:

//生成 0 到 9 之間(包含)均勻分布的隨機數

uniform_int_distribution u(0,9);

default_random_engine e; // 生成無符號隨機整數

for (size_t i =0;i<10; i++)

// 將 u 作為隨機數源

// 每個呼叫返回在指定範圍內並服從均勻分布的值

cout

<" ";

cout

<< endl;

上面的**輸入如下:

0 1 7 4 5 2 0 6 6 9

上面的程式中,我們將u定義為uniform_int_distribution。這種型別生成均勻分布的unsigned值。當我們定義乙個這種型別的物件時,可以提供想要的最小值和最大值。在上面這段**中,u(0,9)表示我們希望得到 0 到 9 之間(包含)的數。隨機數分布類會使用包含的範圍,從而我們可以得到給定整形的每個可能值。

類似引擎型別,分布型別也是函式物件類。分布型別定義了乙個呼叫運算子,它接受乙個隨機數引擎作為引數。分布物件使用它的引擎引數生成隨機數,並將其對映到指定的分布。

傳遞給分布物件的是引擎物件本身,也就是u(e),如果我們將呼叫寫為u(e()),含義就變為將e生成的下乙個值傳遞給u,這會導致乙個編譯錯誤。我們傳遞的是引擎本身,而不是他生成的下乙個值,原因是某些分布可能需要呼叫引擎多次才能得到乙個值。

隨機數發生器有乙個特性,也就是即使生成的樹看起來是隨機的,但是對於乙個給定的發生器,每次執行程式它都會返回相同的數值串行。序列不變這一事實在除錯的時候十分有用,但是另一方面,使用隨機數發生器的程式也必須考慮到這一特性。

下面介紹乙個例子,需要乙個函式生成乙個 vector,包含 100 個均勻分布在 0 到 9 之間的隨機數。一種錯誤的方法是使用下面的**:

vector

bad_randvec()

// 但是 每次呼叫這個函式都會返回相同的 vector

vector

v1(bad_randvec());

vector

v2(bad_randvec());

// 將會列印輸出 equal

cout

<< ((v1==v2) ? "equal" : "not equal") << endl;

上面這段**會輸出equal,因為 vector v1 和 v2 具有相同的值。

正確的定義方法是將引擎和關聯的分布物件定義為 static 的

vector

good_randvec()

由於eu都是 static 的,因此它們在函式呼叫之間會保持住狀態。第一次呼叫會使用u(e)生成的序列中的前 100 個隨機數,第二次呼叫會獲得接下來 100 個。以此類推。

注意,乙個給定的隨機數發生器已知會生成相同的隨機數序列。乙個函式如果定義了區域性的隨機數發生器,應該將其(包括引擎和分布物件)定義為static的。否則,每次呼叫函式都會生成相同的序列。

隨機數發生器會生成相同的隨機數序列這一特性在除錯中很有用。但是,一旦我們的程式除錯完畢,我們通常希望每次執行程式都會生成不同的隨機結果,可以通過提供乙個種子(seed)來達到這個目的。種子就是乙個數值,殷勤可以利用它從序列中乙個新位置重新開始生成隨機數。

為引擎設定種子有兩種方式:

// 幾乎肯定是生成隨機整數 vector 的錯誤方法

// 每次呼叫這個函式都會生成相同的 100 個數

default_random_engine e1; // 使用預設種子

default_random_engine e2(2147483646); // 使用給定的種子值

// e3 和 e4 將會生成相同的序列,因為他們使用了相同的種子

default_random_engine e3;

e3.seed(32767); //呼叫 seed 設定為乙個新種子值

default_random_engine e4(32767); // 將種子值設定為 32767

for(size_t i = 0;i != 10; i++)

{if (e1() == e2())

cout

<<"unseeded match at iteeration: "

cout

<<"seeded differs at itertion: "

程式常常需要乙個隨機浮點數源。特別是程式經常需要 0 到 1 之間的隨機數。

可一定以乙個uniform_real_distribution型別的物件,並讓標準庫來處理從隨機整數到隨機浮點數的對映。與處理uniform_int_distribution一樣,在定義物件時,我們指定最小值和最大值。

default_random_engine e;        // 生成無符號隨機整數

// 0 到 1 (包含)的均勻分布

uniform_real_distributionu(0,1);

for(size_t i =0;i<10;i++)

cout

<" ";

cout

《此外,當我們對分布函式不指定預設生成的型別引數時,程式會自動賦予乙個型別,生成浮點值得分布型別預設生成double型別,生成整型值的分布型別預設生成int型別,如下:

uniform_real_distribution<>u(-1,1); // 預設生成 double 值

除了生成上面的均勻分布,c++ 11 還規定了可以生成 20 種不同的分布型別,比如 均勻分布uniform,正態分佈normal,二項分布binomial,泊松分布poisson,學生分布 student 等等,相關函式可以檢視相應的函式(具體可以參考 c++ primer 781頁)。

C 11 Random庫隨機數

下面 演示使用c 11的random庫進行隨機數的生成 include include using namespace std int main 初始化隨機種子 std mt19937 rng rng.seed std random device 建立乙個均勻分布,這個均勻分布可以等概率 隨機 生成...

C 11 Random庫隨機數

下面 演示使用c 11的random庫進行隨機數的生成 include include using namespace std int main 初始化隨機種子 std mt19937 rng rng.seed std random device 建立乙個均勻分布,這個均勻分布可以等概率 隨機 生成...

Random生成隨機數

random有兩個常用的建構函式,乙個是無參的,乙個是有參的,先來看一段 及執行結果 public class randomtest for int i 0 i 3 i 執行結果如下 無參執行結果 1692516565 無參執行結果 2111480651 無參執行結果 1485452568 有參執行...