(c++11)隨機數------c++程序設計原理與實踐(進階篇)
隨機數既是一個實用工具,也是一個數學問題,它高度復雜,這與它在現實世界中的重要性是相匹配的。在此我們只討論隨機數哦最基本的內容,這些內容可用於簡單的測試和仿真。在<random>中,標準庫提供了復雜的方法來產生適應不同數學分布的隨機數。這一隨機數標準庫基於下面兩個基礎概念:
- 發生器(engine,隨機數發生器):發生器是一個可以產生均勻分布整形值序列的函數對象。
- 分布(distribution):分布是一個函數對象,給定一個發生器產生的序列作為輸入,分布可以按照相應數學公式產生一個值的序列。
例如 http://www.cnblogs.com/goudanli/p/7856623.html 中的 random_vector()函數。調用random_vector(n)就會生成一個Matrix<double,1>類型的矩陣對象,它包含n個元素,元素值都是[0:n)之間的隨機數。
Vector random_vector(Index n) { Vector v(n); default_random_engine ran{(unsigned int)(time(0)+2)}; uniform_int_distribution<> ureal{ 0,max0 }; for (Index i = 0; i < n; ++i) { v(i) = ureal(ran); } return v; }
默認發生器(default_random_engine)簡單、代價底、容易運行。對日常應用,它已經足夠了。對於更專業的應用,標準庫提供了其他發生器,它們有著更好的隨機性和不同的執行代價。例如,linear_congurential_engine、mersenne_twidter_engine和random_device等。
std_lib_facilities.h中的兩個隨機數發生器定義如下
int randint(int min,int max){ static default_random_engine ran; return uniform_int_distribution<>{min,max}(ran); } int randint(int max){ return randint(0,max); }
這些函數經常會被用到,當然還有其他的,讓我們看看正態分布如何產生:
auto gen=bind(normal_distribution<double>{15,4.0}, default_random_engine{});
<functional>中的標準庫函數bind()構造了一個函數對象,當調用它時,它會調用它的第一個參數,並將第二個參數作為這次調用的參數。因而在本例中,gen()返回一個正態分布序列,其均值為15,方差為4.0,使用的是default_random_engine。示例:
vector<int>hist(2*15); for(int i=0;i<500;++i) ++hist[int(round(gen()))]; for(int i=0;i!=hist.size();++i){ cout<<i<<‘\t‘; for(int j=0;j!=hist[i];++j) cout<<‘*‘; cout<<‘\n‘; }
完整程序:
#include<iostream> #include<random> #include<functional> using namespace std; auto gen=bind(normal_distribution<double>{15,4.0}, default_random_engine{}); int main(){ vector<int>hist(2*15); for(int i=0;i<500;++i) ++hist[int(round(gen()))]; for(int i=0;i!=hist.size();++i){ cout<<i<<‘\t‘; for(int j=0;j!=hist[i];++j) cout<<‘*‘; cout<<‘\n‘; } }
輸出:
0 * 1 2 3 * 4 ** 5 * 6 *** 7 ********** 8 ************* 9 ******************* 10 *************** 11 ********************************** 12 ********************************* 13 ************************************** 14 ********************************************************* 15 *************************************************** 16 ********************************************** 17 ****************************************** 18 ************************************* 19 ******************************** 20 **************************** 21 **************** 22 ******** 23 ******* 24 **** 25 ** 26 27 28 29
正態分布經常被用到,其他分布包括 bernoulli_distribution,exponential_distribution和chi_distribution。在《The C++ Programming Language》中能找到詳細介紹。整數分布的返回值是閉區間[a:b],而實數(浮點)分布的返回值是開區間[a:b)。
默認情況下,程序的每次運行中,發生器(除了random_device)產生同樣的序列。這非常有利於程序調試。如果希望同一發生器產生不同的序列,我們需要設定不同的初值。這一初始化過程被稱為“種子”。例如:
auto gen1= bind(uniform_int_distribution<>{0,9}, default_random_engine{}); auto gen2= bind(uniform_int_distribution<>{0,9}, default_random_engine{10}); auto gen3= bind(uniform_int_distribution<>{0,9}, default_random_engine{5});
為了獲得不可預測的序列,我們經常使用當前時間(以納秒為單位)或其他類似的事物作為種子。
c++程序設計原理與實踐(進階篇)
(c++11)隨機數------c++程序設計原理與實踐(進階篇)