17.4 随机数
头文件 random
通过一组协作的类来解决随机问题
引擎类:生成unsigned 随机数序列
分布类:使用一个引擎类生成指定类型的,在给定范围内的,服从特定概率分布的随机数
17.4.1 随机数引擎和分布
default_random_engine e;
for (size_t i = 0; i < 10; ++i)
{
//e()调用对象来生成下一个随机数, e是一个类对象,它有一个函数调用
cout << e() << " ";
}
cout << endl;
//分布类型和引擎
//分布类型对象生成0到9之间均匀分布的随机数
uniform_int_distribution<unsigned>u(0, 9);
//随机数发生器时,是指分布对象和引擎对象的组合
for (size_t i = 0; i < 10; ++i)
{
//将u作为随机数源
//每个调用返回在指定范围内并服从均匀分布的值
cout << u(e) << " ";
}
比较随机数引擎和rand函数
//对比C库函数rang 引擎类型的范围可以通过该类型对象的min和max成员来获得
cout << "min= " << e.min() << " max= " << e.max() << endl;
引擎生成一个数值序列
下面的代码解决了如何生成新的数值序列,使用static
vector<unsigned>bad_randVec()
{
default_random_engine e;
uniform_int_distribution<unsigned>u(0, 9);
vector<unsigned>ret;
for (size_t i = 0; i < 100; ++i)
{
ret.push_back(u(e));
}
return ret;
}
int main()
{
//几乎肯定是生成随机整数vector的错误方法
//每次调用这个函数都会生成相同的100个数
vector<unsigned>v1(bad_randVec());
vector<unsigned>v2(bad_randVec());
//输出equal
cout << ((v1 == v2 ? "equal" : "not equal")) << endl;
生成·随机数的static
vector<unsigned>bad_randVec()
{
static default_random_engine e;
static uniform_int_distribution<unsigned>u(0, 9);
vector<unsigned>ret;
for (size_t i = 0; i < 100; ++i)
{
ret.push_back(u(e));
}
return ret;
}
一个给定的随机数发生器一直会生成相同的随机数序列,一个函数如果定义了局部的随机数发生器,应该将其定位为static
包含引擎和分布对象。否则每次都会生成相同的序列
设置随机数发生器种子
//默认种子
default_random_engine e1(time(0));
//使用给定的种子值
default_random_engine e2(9);
//e3和e4将生成相同的序列,因为它们使用了相同的种子
//调用seed设置一个新种子值
default_random_engine e3;
e3.seed(32767);
//讲种子设置为32767
default_random_engine e4(32767);
for (size_t i = 0; i != 100; ++i)
{
if (e1() == e2())
{
cout << "unseedd match at ieration: " << i << endl;
}
if (e3() != e4())
{
cout << "seeded differs at ieration: " << i << endl;
}
}
稍微随机些的种子 但作为一个自动过程的一部分反复运行 将time的返回值作为种子的方式就无效了
它可能多次使用的都是相同的种子
default_random_engine e1(time(0));
17.4.1节练习: 做一个返回随机unsigned int 的函数
unsigned random_val()
{
static default_random_engine e(time(0));
static uniform_int_distribution<unsigned>u(0, 100);
return u(e);
}
int main()
{
for(auto i = 0; i < 50; ++i)
{
cout << random_val() << endl;;
}
}
17.4.2 允许用户提供一个种子作为可选参数
unsigned random_val(long seed = -1)
{
static default_random_engine e(time(0));
static uniform_int_distribution<unsigned>u(0, 100);
if (seed >= 0)
{
e.seed(seed);
}
return u(e);
}
int main()
{
for (auto i = 0; i < 50; ++i)
{
cout << random_val(12) << " ";
}cout << endl;
for (auto i = 0; i < 50; ++i)
{
cout << random_val() << " ";
}cout << endl;
for (auto i = 0; i < 50; ++i)
{
cout << random_val(1) << " ";
}cout << endl;
17.4.3 在添加两个参数,表示函数返回最小值和最大值
unsigned random_val(long seed = -1,long min =0,long max=999)
{
static default_random_engine e(time(0));
static uniform_int_distribution<unsigned>u(0, 999);
if (seed >= 0)
{
e.seed(seed);
}
if (min < max)
{
u=uniform_int_distribution<unsigned>(min,max);
}
return u(e);
}
int main()
{
for (auto i = 0; i < 10; ++i)
{
cout << random_val() << " ";
}cout << endl;
for (auto i = 0; i < 10; ++i)
{
cout << random_val() << " ";
}cout << endl;
for (auto i = 0; i < 10; ++i)
{
cout << random_val(1,0,9) << " ";
}cout << endl;
for (auto i = 0; i < 10; ++i)
{
cout << random_val(12412,3333,44444) << " ";
}cout << endl;
17.4.2其他随机数分布
生成随机实数
//生成无符号随机整数
default_random_engine e;
//0到1的均匀分布
uniform_real_distribution<double>u(0, 1);
for (size_t i = 0; i < 10; ++i)
{
cout << u(e) << " ";
}
使用分布的默认结果类型
//空<>表示使用默认结果类型
uniform_real_distribution<>cc(0,1); //默认生成double值
for (size_t i = 0; i < 10; ++i)
{
cout << cc(e) << " ";
}
生成非均匀分布的随机数
normal_distribution<>n(4, 1.5);重点,这里面有一些算法我不懂,当肯定是围绕着4均值和这个标准差1.5进行的,
normal_distribution<>n(100, 1.5),他也是围绕着100进行的,和标准差有很大的关系,他的最大值和最小值在0~8位置中,100在中间这个位置,以标准差进行求数,
//生成随机数整数
default_random_engine e;
//均值4,标准差1.5
normal_distribution<>n(4, 1.5);
//9个元素均为0
vector<unsigned>vals(9);
for (size_t i = 0; i != 200; ++i)
{
//舍入到最接近的整数
unsigned v = lround(n(e));
//如果结果在范围内
if (v < vals.size())
{
//统计每个数出现了多少次
++vals[v];
}
}
for (size_t j = 0; j != vals.size(); ++j)
{
cout << j << ":" << string(vals[j], '*') << endl;
}
bernoulli_distribution类
bool play(bool x)
{
int i;
cout << "请猜一个数字" << endl;
cin >> i;
if (i > 10)
{
return true;
}
else
{
return false;
}
}
void test08()
{
string resp;
//e应保持状态,所以必须在循环外定义
default_random_engine e;
//默认是50/50的机会
bernoulli_distribution b;
do
{
bool first = b(e); //如果为true ,则程序先行
cout << (first ? "We go first" : "You get to go first") << endl;
//传递谁先行的指示,进行游戏
cout << ((play(first)) ? "sorry, you lost" : "congrats, you won") << endl;
} while (cin >> resp && resp[0] == 'Y');
}
17.4.2节练习 答案链接https://zhuanlan.zhihu.com/p/362081113
17.31:do循环内定义b和e,
由于引擎返回相同的随机序列,所以我们必须在循环外面声明引擎对象
。否则,每步循环都会创建一个新引擎,从而每步循环都会生成相同的值,类似的,分布对象也要保持状态,因此也在循环外定义
17.32:循环体外定义resp,
{}外部识别不出resp,直接报错
17.33
#include<iostream>
#include<fstream>
#include<map>
#include<string>
#include<sstream>
#include<random>
#include<vector>
#include<time.h>
using namespace std;
void word_transform(ifstream& map_file, ifstream& input);
map<string, vector<string>>bulidMap(ifstream& map_file);
const string& transform(const string& s, const map<string, vector<string>>& m);
int main(int argc,char **argv)
{
//if (argc != 3)
//{
// cerr << "文件名错误!" << endl;
// exit(1);
//}
ifstream in_map_file("D:\\c++primer\\第十七章\\04随机数引擎和分布\\随机数引擎\\随机数引擎\\11.33.txt");
if (!in_map_file)
{
cerr << "打开map_file文件失败!" << endl;
exit(1);
}
ifstream in_string_file("D:\\c++primer\\第十七章\\04随机数引擎和分布\\随机数引擎\\随机数引擎\\11.33_string.txt");
if (!in_string_file)
{
cerr << "打开string_file文件失败!" << endl;
exit(1);
}
word_transform(in_map_file, in_string_file);
}
void word_transform(ifstream& map_file, ifstream& input)
{
//把文件内容读到map<string,vector<string>>
auto trans_map = bulidMap(map_file);
//临时存储一行input文件的内容
string line_word;
//读取一行
while (getline(input, line_word))
{
istringstream line_word2(line_word);
//存储一个单词
string word;
//控制是否打印空格
bool firstwod = true;
while (line_word2 >> word)
{
if (firstwod)
{
firstwod = false;
}
else
{
//在单词间打印空格
cout << " ";
}
//打印输出
cout << transform(word, trans_map);
}
cout << endl;
}
}
map<string, vector<string>>bulidMap(ifstream& map_file)
{
//允许多种转换方法
//转换的单词和替换的内容
string key, value;
//保存转换规则
map<string, vector<string>>map_ss;
//读取第一个单词到key中,行中剩余的内容存入value
while (map_file >> key && getline(map_file, value))
{
istringstream line_value(value);
//检测是否有转换规则
if (value.size() > 1)
{
while (line_value >> value)
{
//跳过前导空格
map_ss[key].push_back(value);
}
}
else
{
throw runtime_error("no rult for" + key);
}
}
return map_ss;
}
const string& transform(const string& s, const map<string, vector<string>>& m)
{
static default_random_engine e(time(0));
//找到关键字s,返回一个迭代器
auto iter = m.find(s);
//单词转换映射表中
if (iter != m.cend())
{
//随机分布
uniform_int_distribution<unsigned>u(0, iter->second.size() - 1);
return iter->second[u(e)];
}
else
{
return s; //返回原单词
}
}