C++生成随机数
作者:互联网
随机数通过 随机数引擎类 和 随机数分布类。
引擎类可以生成 unsigned(无符号数) 随机数序列;分布类使用一个引擎类生成指定类型的、在给定范围内的、服从特定概率分布的随机数。
它们定义在头文件 random 中。
随机数引擎:
随机数引擎是函数对象类,它们定义了一个调用运算符,该运算符不接受参数并 返回一个随机 unsigned 整数。
上代码:
default_random_engine e;//生成随机无符号数(原始随机数)
int i = 100;
for (int i = 0; i < 10; i++)
{
cout << e( ) << endl;//调用对象 e 来生成10个随机数
}
上面程序输出 :
以下《C++ primer 》 :
分布类型:
uniform_int_distribution<unsigned> u(1, 100);//生成1到100(包含100)之间的均匀分布的随机数
default_random_engine e;//生成随机无符号数(原始随机数)
for (int i = 0; i < 100; i++)
{
cout << u(e) << endl;//将 u 作为随机数源
}
分布类型也是函数对象类。它接受一个随机数引擎作为参数。
我们传递给分布对象的是引擎对象本身。不能写成 : u ( e() ).
随机数发生器就是指分布对象和引擎对象的组合。
cout << e.min() << " " << e.max() << endl;//获得随机数引擎的范围
我们上面所写的代码生成一次随机数,第二次再生成就会是相同的,这并不能达到我们想的真正的随机数。
我们可以把引擎和分布对象定义为 static 的,让它保持状态:
#include <iostream>
#include<random>
using namespace std;
#include<vector>
static default_random_engine e;
static uniform_int_distribution<unsigned> u(1, 100);
vector<unsigned> doo()
{
vector<unsigned> ret;
for (int i = 0; i < 10; i++)
{
ret.push_back(u(e));//向容器中添加元素
}
for (auto i : ret)//利用范围 for 输出
{
cout << i<<" ";
}
return ret;
}
int main() {
doo(); //13 3 35 86 5 92 30 86 99 4
cout << endl;
doo(); //36 66 41 27 40 21 20 5 98 7
cout << '\n';
doo();// 10 10 44 40 47 27 37 54 61 72
system("pause");
return 0;
}
一个给定的随机数发生器一直会生成相同的随机数序列。我们可以通过设置随机数发生器种子来实现真正的随机数。
每次运行程序都会生成不同的随机结果,我们可以通过提供一个种子来达到目的。
为引擎设置种子的两种方式:在创建引擎对象 时提供种子,或者调用引擎的 seed 成员。
default_random_engine e1;//使用默认种子值
default_random_engine e2(32767);//给定种子值
default_random_engine e3;
for (int i = 0; i < 10; i++)
{
cout << e1() <<" ";
}
cout << endl;
for (int i = 0; i < 10; i++)
{
cout << e2() << " ";
}
cout << endl;
e3.seed(32767);//调用 seed 设置一个新种子值
for (int i = 0; i < 10; i++)
{
cout << e3() << " ";
}
上面代码中本来 e1 和 e3 都是使用默认的种子值,它们两个生成的随机数序列将会是相同的。e2是我们自己给定的,它和 e1 和 e3 和种子值不同,因些 e2 生成的随机数序列不会是其他两个是一样的。后面我们通过调用 seed 函数为 e3 重新设置了一个种子值,和 e2的一样,又变成了 e2 和 e3 是生成相同的随机数序列。
选择一个好种子是极其困难的: 最常用的方法就是调用系统函数 time , 这个函数定义在头文件 ctime 中,它返回一个特定时刻到当前经过了多少秒。
default_random_engine e2(time(0));//给定种子值
uniform_int_distribution<int> u(0, 100);
cout << endl;
for (int i = 0; i < 10; i++)
{
cout <<u(e2) << " ";//第次调用的结果几乎都会不一样
}
time返回以秒计的时间,因此这种方式只适用于生成种子的间隔为秒级或更长的时间。
生成随机浮点数:
我们定义一个 uniform_real_distribution 类型的对象,让标准库来处理从随机数到随机浮点数的映射。
default_random_engine e2(time(0));//给定种子值
uniform_real_distribution<float> u(0, 1);
for (int i = 0; i < 10; i++)
{
cout <<u(e2) << " ";//每次调用都会不同的浮点数
}
分布类型的操作:
分布类型都是模板,具有单一的模板类型参数,每个分布模板都有一个默认模板实参。
uniform_real_distribution < > u1(0, 1); //空尖表示我们想使用默认结果类型,默认生成 double 值
uniform_int_distribution <> u2(0, 100); // 默认生成 unsigned 值
生成非均匀分布的随机数:
normal_distribution 生成浮点值。
default_random_engine e2(time(0));//给定种子值
normal_distribution<> n(10, 1.3);
for (int i = 0; i < 10; i++)
{
cout <<lround(n(e2)) << " ";//lround 函数浮点数舍入到最接近的整数。它定义在头文件cmath中
}
bernoulli_distribution类:
它是一个普通类,不接受模板参数。它总是返回一个 bool 值,它返回 true 的概率是一个常数,默认为 0.5;
default_random_engine e2(time(0));//给定种子值
bernoulli_distribution b;
for (int i = 0; i < 10; i++)
{
cout <<b(e2) << " ";//它返回的真假的次数是相同的,因为默认的概率是一样的
}
使用它的原因是允许我们调整随机的概率:
bernoulli_distribution b; //默认是 50/50 的机会
bernoulli_distribution b(.55);//代表程序有55/45机会
引擎返回相同的随机数序列,所以我们必须要循环外声明引擎对象。不然第次循环都会创建一个新引擎,从而每次都会生成相同的值,分布对象在要保持状态,也应该在循环外面。
其他的扩展感兴趣可以自己看看(来自书《C++ primer》):
标签:int,random,C++,生成,引擎,随机数,distribution 来源: https://blog.csdn.net/m0_57035799/article/details/120789427