c++primer第十七章 04随机数

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; //返回原单词
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值