C++11 随机数生成
C++ 程序中,在新标准出现之前,C 和 C++ 都依赖一个C 库函数 rand 来产生随机数,然而,这个函数生成的是均匀分布的伪随机数,每个随机数的范围在 0 和一个最大值RAND_MAX(至少为 32767)之间。
rand 函数存在一些问题:在实际的编程中,很多程序需要不通范围的随机数。一些应用需要随机浮点数。一些程序需要非均匀分布的随机数。所在在编写程序时为了生成满足一定要求的随机数,通常会转换 rand 生成的随机数的范围、类型或者是分布,但是这样会引入非随机性。
c++11提供的<random>实现了随机数库,它通过随机数引擎类(random_number_engines)产生随机数序列,随机数分布类(random_number_distribution)使用随机数引擎生成服从特定概率分布的随机数。
下面介绍一个C++中生成随机数的例子:
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
//#include "Timer.h"
#include <random>
// const int arraySize = 100000;
int main()
{
std::default_random_engine e; // 默认的随机数引擎
for (int i = 0; i < 15; i++)
{
auto rnd = e();
std::cout << rnd << std::endl;
std::cout << typeid(rnd).name() << std::endl; // 返回值的类型
}
std::cout << e.max() << " | " << e.min() << std::endl; // 随机数引擎的范围
//system("pause");
return 0;
}
随机数类是定义在std命名空间的,所以要声明。随机数引擎是函数对象,这就是为什么使用e()去生成随机数。程序每次运行都会生成相同的随机数序列,这在一定程度有利于程序的调试,但我们有时需要每一次运行产生的随机数序列都是不同的。我们可以通过设置随机数引擎的种子来改变引擎的状态,没有改变时是使用默认的随机数种子,这就是为什么每一次都生成同样的随机数序列。从结果我们可以知道,默认的种子生成随机数范围在1-2147483646之间。
可以通过e.seed()方法来设置随机数种子:
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
//#include "Timer.h"
#include <random>
// const int arraySize = 100000;
int main()
{
std::default_random_engine e; // 默认的随机数引擎
e.seed(10); // 设置生成随机数的种子
for (int i = 0; i < 15; i++)
{
auto rnd = e();
std::cout << rnd << std::endl;
//std::cout << typeid(rnd).name() << std::endl; // 返回值的类型
}
std::cout << e.max() << " | " << e.min() << std::endl; // 随机数引擎的范围
//system("pause");
return 0;
}
如果需要改变生成的随机数的范围,需要使用随机数分布类:
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
//#include "Timer.h"
#include <random>
// const int arraySize = 100000;
int main()
{
std::default_random_engine e; // 默认的随机数引擎
std::uniform_int_distribution<int> u(0, 10); // 随机数分布类,可以确定随机数范围 [0,10]
e.seed(10); // 设置生成随机数的种子
for (int i = 0; i < 15; i++)
{
auto rnd = u(e);
std::cout << rnd << " ";
//std::cout << typeid(rnd).name() << std::endl; // 返回值的类型
}
std::cout << std::endl;
std::cout << e.max() << " | " << e.min() << std::endl; // 随机数引擎的范围
//system("pause");
return 0;
}
在实际的应用中,[0, 1]之间的随机数应用的比较广泛,在C++11中,可以按照如下的方式生成满足要求的随机数:
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
//#include "Timer.h"
#include <random>
// const int arraySize = 100000;
int main()
{
std::default_random_engine e; // 默认的随机数引擎
std::uniform_real_distribution<double> u(0, 1); // 随机数分布类,可以确定随机数范围 [0,10]
e.seed(10); // 设置生成随机数的种子
for (int i = 0; i < 15; i++)
{
auto rnd = u(e);
std::cout << rnd << " ";
//std::cout << typeid(rnd).name() << std::endl; // 返回值的类型
}
std::cout << std::endl;
std::cout << e.max() << " | " << e.min() << std::endl; // 随机数引擎的范围
//system("pause");
return 0;
}
除此之外,c++11的<random>库还提供了不同的随机数引擎和随机数分布类,例如,要生成满足正态分布的0-1之间的随机数:
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
#include "Timer.h"
#include <random>
// const int arraySize = 100000;
int main()
{
std::default_random_engine e; // 默认的随机数引擎
// std::normal_distribution的构造函数 可知参数的意义
// explicit normal_distribution(_Ty _Mean0 = 0.0, _Ty _Sigma0 = 1.0)
std::normal_distribution<double> u(0, 1); // 正态分布
e.seed(10); // 设置生成随机数的种子
for (int i = 0; i < 15; i++)
{
auto rnd = u(e);
std::cout << rnd << " ";
//std::cout << typeid(rnd).name() << std::endl; // 返回值的类型
}
std::cout << std::endl;
std::cout << e.max() << " | " << e.min() << std::endl; // 随机数引擎的范围
//system("pause");
return 0;
}
C++11 提供的随机数引擎和随机数分布类型如下所示:
http://www.cplusplus.com/reference/random/?kw=random
随机数引擎:
随机数分布类:
------------------------------------------------------------------------------------------------------