随机数生成

来源:互联网 发布:linux执行命令 编辑:程序博客网 时间:2024/05/21 15:44

C++ API:

http://www.cplusplus.com/reference/random/uniform_int_distribution/

C++11往库里加了不少良心设施,新版的随机数发生器就是其中之一。

之所以需要全新的随机数设施想必是因为原来的太难用。

事实呢?嗯,旧的设施真的很难用。

旧式的随机数发生器沿用C的 Rand() 函数,这个函数会产生区间在\([0, \text{RAND_MAX}]\)的伪随机数,且随机数近似可以看做符合均匀分布。

传统做法的弊端大致有两个:

  1. 经常需要做人肉变换随机数产生区间,且人肉变换过程中极易破坏原有的分布性质
  2. 难以产生符合制定分布的随机数

相比下,新设施针对这两点做了很大的改进。

新设施利用两部分来生成随机数:

  • random number engines . 负责生成原始随机数
  • random number distributions . 迫使生成的随机数在统计上满足指定的概率分布

STL预先指定了一系列的生成引擎,并且提供一个 default_random_enginedefault_random_engine 会使用某个预定义的引擎,且不同编译器,不同平台的实现可能不同。

PS:有关详细的预定义引擎列表,可以参见 这里

下面是一个使用默认引擎的实例:

    
1
2
3
4
5

std :: default_random_engine e;

for ( size_t i =0 ; i < 10 ; i ++ ) {

     cout << e () << endl ;

}

默认情况下,引擎产生的随机数范围在 default_randm_engine::mindefault_random_engine::max 之间。

有了引擎,我们可以指定随机数要符合的分布性质,例如说,在\([5,20]\)上的均匀分布

    
1
2
3
4
5

std :: default_random_engine e;

std :: uniform_int_distribution <>u ( 5 , 20 ) ;

for ( size_t i =0 ; i < 10 ; i ++ ) {

     cout << u (e ) << endl ;

}

因为我们是利用引擎在制定分布上产生随机数,所以这里我们要将引擎对象传入给分布对象。

库提供了相当完善的概率分布类,详细的列表可以参见上面那个URL。

关于种子

由于目前使用的伪随机数都是根据一个起始数(通称为种子)来得到一个周期很大的数列,所以保证每次使用随机数时初始化的种子不同对随机数的质量有很重要的作用。

传统做法是利用 time(NULL) 去初始化种子,这个做法在这里也可以继续使用:

    
1
2
3

std :: default_random_engine e( time ( nullptr )) ;

std :: uniform_int_distribution <>u ( 5 , 20 ) ;

}

不过,由于 time 的精度是秒,所以在某些极端情况下,这也并不是一个非常好的选择。

幸运的,C++11提供了一个非常友好的类: random_device 。这个类的作用是,可以产生non-deterministic random numbers .

这个类 有可能 产生真正的随机数,不过真是效果和具体实现有关。某些平台可能才用伪随机数作为底层实现也说不定呢…

显然的,我们可以利用 random_device 去初始化我们的随机数种子   

1
2
3
4
5
6

std :: random_device rd ;

std :: default_random_engine e( rd ( ) ) ;

std :: uniform_int_distribution <>u ( 5 , 20 ) ;

for ( size_t i =0 ; i < 10 ; i ++ ) {

     cout << u (e ) << endl ;

}          

C++中函数uniform_int_distribution 的官网API:

http://www.cplusplus.com/reference/random/uniform_int_distribution/


0 0