(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++程序设计原理与实践(进阶篇)

时间: 2024-10-10 01:41:53

(c++11)随机数------c++程序设计原理与实践(进阶篇)的相关文章

实现求解线性方程(矩阵、高斯消去法)------c++程序设计原理与实践(进阶篇)

步骤: 其中A是一个n*n的系数方阵 向量x和b分别是未知数和常量向量: 这个系统可能有0个.1个或者无穷多个解,这取决于系数矩阵A和向量b.求解线性系统的方法有很多,这里使用一种经典的方法--高斯消去法(https://zh.wikipedia.org/wiki/高斯消去法).首先,我们对A和b进行交换,使得A变为一个上三角矩阵.上三角矩阵就是对角线之下的所有元素均为0.即如下形式: 实现这个目标是很容易的.为了使a(i,j)变为0,我们先将它乘以一个常量,使它等于第j列上的另一个元素,比如说

编码原则实例------c++程序设计原理与实践(进阶篇)

编码原则: 一般原则 预处理原则 命名和布局原则 类原则 函数和表达式原则 硬实时原则 关键系统原则 (硬实时原则.关键系统原则仅用于硬实时和关键系统程序设计) (严格原则都用一个大写字母R及其编号标识,而推荐原则都用小写字母r及其编号标识,对于前者程序员必须严格遵守,而后者则偶尔可以不遵守) 1.一般原则 R100:任何函数和类的代码规模都不应超过200行(不包括注释). 原因:长的函数和类会更复杂,因而难以理解和测试. r101:任何函数和类都应该能完全显示在一屏上,并完成单一的逻辑功能.

bitest(位集合)------c++程序设计原理与实践(进阶篇)

标准库模板类bitset是在<bitset>中定义的,它用于描述和处理二进制位集合.每个bitset的大小是固定的,在创建时指定: bitset<4> flags; bitset<128> dword_bits; bitset<12345> lots; 默认情况下,bitset被初始化为全0,但通常我们都会给它一个初始值,可以是一个无符号的整数或者"0"和"1"组成的字符串.例如: bitset<4> fl

有符号数和无符号数------c++程序设计原理与实践(进阶篇)

有符号数与无符号数的程序设计原则: 当需要表示数值时,使用有符号数(如 int). 当需要表示位集合时,使用无符号数(如unsigned int). 有符号数和无符号数混合运算有可能会带来灾难性的后果.例如: vector<int> v; for(int i=0;i<v.size();++i)cout<<v[i]<<'\n'; 易实现版本: unsigned char max=160; //非常大 for(signed char i=0;i<max;i++)

数值限制------c++程序设计原理与实践(进阶篇)

每种c++的实现都在<limits>.<climits>.<limits.h>和<float.h>中指明了内置类型的属性,因此程序员可以利用这些属性来检查数值限制.设置哨兵机制等等.它们对于开发底层程序是非常重要的.如果你觉得需要这些属性值,表明你的工作很可能比较靠近硬件.但这些属性还有其他用途,例如,对语言实现细节感到好奇是很正常的:"一个int有多大?","char是有符号的吗?"等等.希望从系统文档中找到这些问题

C++程序设计原理与实践 第十九章部分答案

1 #include <iostream> 2 #include <vector> 3 #include <string> 4 using namespace std; 5 6 template<class T> void f(vector<T>&v1,vector<T>&v2) //v2不设为const因为可能v2=v1 习题1 7 { 8 if(v1.capacity()<=v2.size()) 9 { 10

C++程序设计原理与实践 第十章部分答案

1 #include "../../st.h" 2 3 class Point{ 4 public: 5 Point():x(0),y(0){} 6 Point(int x1,int y1):x(x1),y(y1){} 7 double re_x(){return x;} 8 double re_y(){return y;} 9 friend istream& operator>>(istream&is,Point&p); 10 private: 1

C++程序设计原理与实践 第十七章部分答案

1 #include <iostream> 2 using namespace std; 3 4 void to_lower(char* s) 5 { 6 while(*s!='\0') 7 { 8 if(*s>='A'&&*s<='Z') 9 *s+=32; 10 s++; 11 } 12 } 13 14 char* strdup1(const char*s) 15 { 16 char *p=new char[]; 17 cout<<sizeof(s)

C++程序设计原理与实践 第十一章部分答案

1 #include "../../st.h" 2 3 int main() 4 try{ 5 string s1="a.txt"; 6 string s2="z.txt"; 7 ifstream ifs(s1.c_str()); 8 if(!ifs) 9 error("can not open input file",s1); 10 ofstream ofs(s2.c_str()); 11 if(!ofs) 12 error