C风格的随机数
srand和rand
srand ——产生随机数种子 rand()%n ——产生0~n随机数 rand()%n+1 产生1~n随机数
/* rand example: guess the number */
#include <stdio.h> /* printf, scanf, puts, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
int main ()
{
int iSecret, iGuess;
/* initialize random seed: */
srand (time(NULL));
/* generate secret number between 1 and 10: */
iSecret = rand() % 10 + 1;
do {
printf ("Guess the number (1 to 10): ");
scanf ("%d",&iGuess);
if (iSecret<iGuess) puts ("The secret number is lower");
else if (iSecret>iGuess) puts ("The secret number is higher");
} while (iSecret!=iGuess);
puts ("Congratulations!");
return 0;
}
全局随机数种子——避免多次调用 srand 引起 rand 产生同一随机数
这套伪随机有个问题,如果调用的时间间隔不是以秒为数量级 每次出来的随机数都相同。调用速度太快,使得每次srand 初始化随机数种子。
auto rdm = [](){
srand(time(0));
for(int i = 0;i<5;++i){
cout << rand()%10<< '\t';}
cout<<'\n';};
for(int j = 0;j<5;++j)
rdm();
/*输出举例
9 0 1 6 7
9 0 1 6 7
9 0 1 6 7
9 0 1 6 7
9 0 1 6 7
*/
全局的随机数种子,可以把srand() 放到函数外,全局初始化随机数种子一次,解决这一问题 ???不理解,我浅薄的理解随机数有周期(65536),如果每次在lambda表达式里初始化,就从头开始走,如果全局初始化,就不会走上一次走过的路径,所以一样。详见参考文献。
这样写
srand(time(0));
auto rdm = [&](){
for(int i = 0;i<5;++i){
cout << rand()%10<< '\t';
}
cout<<'\n';
};
for(int j = 0;j<5;++j)
rdm();
/*输出距离
3 4 8 4 1
2 2 6 6 9
8 9 6 7 6
9 8 2 1 0
8 5 2 0 7
*/
出来结果就随机了,即使多次运行程序每次出来的
5
×
5
5\times5
5×5矩阵也是不同的。
参考文献
C++ rand 与 srand 的用法
C++随机数
<random> 引入下面两类随机数库
- random-number engines 随机数引擎,生成随机unsigned整数序列
- random-number distribution 随机数分布,使用引擎返回特定概率分布的随机函数
C++ 程序不应该使用库函数rand ,而应使用default_random_engine 类和恰当的分布类对象。
random-number engines 随机数引擎
产生原始随机数,基本用法如下
std::default_random_engine e;
for(int i = 0;i<10; ++i)
cout << e() << " ";
//示例输出 16807 282475249 1622650073 984943658 1144108930 470211272 101027544 1457850878 1458777923 2007237709
static 避免随机数序列不变
和刚才rand 一样。
auto rdm = [&](){
default_random_engine e;
for(int j =0;j<5;++j)
cout << e() <<'\t';
cout <<'\n';
};
for(int i = 0;i<5;++i)
rdm();
/*示例输出
16807 282475249 1622650073 984943658 1144108930
16807 282475249 1622650073 984943658 1144108930
16807 282475249 1622650073 984943658 1144108930
16807 282475249 1622650073 984943658 1144108930
16807 282475249 1622650073 984943658 1144108930
*/
为了避免这一问题只要用static 使得随机数引擎全局化即可
static std::default_random_engine e;
random-number engines vs random_device
random device 用法详见std::random_device
starkflow 上的说法
std::random_device conceptually produces true random numbers. Some implementations will stall if you exhaust the system’s source of entropy so this version may not perform as well.
std::default_random_engine is a pseudo-random engine. Once seeded, with an random number it would be extremely difficult (but not impossible) to predict the next number.
There is another subtle difference. std::random_device::operator() will throw an exception if it fails to come up with a random number.
Question 2: Which is better?
It depends. For most cases, you probably want the performance and temporal-determinism of the pseudorandom engine seeded with a random number, so that would be the second option.
关于这个问题的讨论详见random_device vs default_random_engine
random-number distribution 随机数分布
uniform_int_distribution基本用法
static default_random_engine e;
static uniform_int_distribution<unsigned> u(0,10);//[0,10]
for(int i = 0;i<10;++i)
cout << u(e) <<' ';//产生0——10 下闭 上闭 伪随机
注意
static 使得伪随机引擎全局化,避免产生重复序列- u 接受参数 为 e而非e()
正态分布 normal distribution
std::default_random_engine e;
std::normal_distribution<double> n(4.0,1.5);
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 i =0;i<vals.size();++i)
cout <<i <<':' << string(vals[i],'*')<<'\n';
/*
示例输出
0:***
1:********
2:********************
3:**************************************
4:**********************************************************
5:******************************************
6:***********************
7:*******
8:*
*/
详见normal distribtion
|