码迷,mamicode.com
首页 > 编程语言 > 详细

C/C++ 中随机数的用法

时间:2014-11-28 06:15:09      阅读:353      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   ar   color   os   sp   for   

本文分两部分,先介绍 C 语言中与随机数相关的两个函数 srand 和 rand,后介绍 C++ 中的 random 库。


1、C 语言中的 srand 和 rand


1)实现

下面是 VC 的实现:
  1. #define RAND_MAX 32767  // in <stdlib.h>  
  2.   
  3. unsigned long _Randseed = 1;    // global seed  
  4.   
  5. void srand(unsigned int seed) {  
  6.     _Randseed = seed;  
  7. }  
  8.   
  9. int rand(void) {  
  10.     _Randseed = _Randseed * 1103515245 + 12345;  
  11.   
  12.     return ((unsigned int)(_Randseed >> 16) & RAND_MAX);  
  13. }  

第一次接触 C 语言中的随机数时,很疑惑为什么有种子这个玩意,只提供一个产生随机数的函数不就行了吗,看了上面的源码后,就明白了,因为计算机不能产生真正的随机数,只能靠数学的方法产生伪随机数。srand 函数的作用是设置种子,如果不设置的话种子(上面的 _Randseed)则默认初始是1,种子是全局变量。rand 的实现就跟数论有关了,可以看到它的返回值范围是 [0, RAND_MAX],标准也是这么规定的。


2)time

既然计算机不能产生真正的随机数,那怎么才能使程序每次运行的结果不同呢?总得有个随机的东西,那就借助 time 这个函数产生种子,引入一个新东西又会带来一些坑,我早年写过这种程序:

  1. // 生成十个随机数(错误用法)  
  2. for (int i = 0; i < 10; ++i) {  
  3.     srand((unsigned int)time(NULL));  
  4.     printf("%d: %d\n", i, rand());  
  5. }  
它将产生10个相同的数。要解释这个问题,就得弄懂 time 这个函数,它的函数原型如下:
  1. time_t time(time_t *timer);  

它返回“当前时间”,这个“时间“的类型是 time_t,在 VC 中被 typedef 为 unsigned long,标准中只规定它是个算数类型,至于它是如何表示时间的未定义。一般是返回 UNIX 时间戳,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。上面的程序执行时很快,在一秒内完成循环,所以它产生了相同的随机数。


3)my_rand

下面提供三个生成随机数的模板

  1. /* 
  2. ** return a random integer in the interval 
  3. ** [0, RAND_MAX] 
  4. */  
  5. int my_rand() {  
  6.     static int is_first = 1;  
  7.     if (is_first) {  
  8.         is_first = 0;  
  9.         srand((unsigned int)time(NULL));  
  10.     }  
  11.   
  12.     return rand();  
  13. }  
  14.   
  15. /* 
  16. ** return a random integer in the interval 
  17. ** [a, b] 
  18. */  
  19. int uniform_int(int a, int b) {  
  20.     static int is_first = 1;  
  21.     if (is_first) {  
  22.         is_first = 0;  
  23.         srand((unsigned int)time(NULL));  
  24.     }  
  25.   
  26.     return (int)((double)rand() / ((RAND_MAX + 1.0) / (b - a + 1.0)) + a);  
  27. }  
  28.   
  29. /* 
  30. ** return a random real in the interval 
  31. ** [a, b] (also [a, b)) 
  32. */  
  33. double uniform_real(double a, double b) {  
  34.     static int is_first = 1;  
  35.     if (is_first) {  
  36.         is_first = 0;  
  37.         srand((unsigned int)time(NULL));  
  38.     }  
  39.   
  40.     return (double)rand() / ((double)RAND_MAX / (b - a)) + a;  
  41. }  
它 们可单独调用,当初始同时调用 uniform_int 和 uniform_real 时,它们将产生两个很接近的数,如果在意这一点的话可以把 srand 放到外面,只调用一次 srand。当要求的随机数范围过大时,uniform_int 和 uniform_real 貌似有 bug。


2、C++ 中的 random 库


在 random 库中有随机数发生器(random engine/generator)和分布(distribution),它们的具体用法我就不在这不说了。我个人认为 engine 存储了种子,将 C 语言中的全局种子封装起来了。uniform distribution 中只存储了最大值和最小值(即平均分布的两个参数)。还有个真正的 engine 叫 std::random_device,它根据机器的各种实时参数产生随机数,貌似有的编译器不支持,产生的还是伪随机数,不过 GCC 是支持的。
同样地,下面提供两个模板。
  1. /* 
  2. ** return a random integer in the interval [a, b] 
  3. */  
  4. int uniform_int(int a, int b) {  
  5.     static std::default_random_engine e{std::random_device{}()}; // avoid "Most vexing parse"  
  6.     static std::uniform_int_distribution<int> u;  
  7.   
  8.     return u(e, decltype(u)::param_type(a, b));  
  9. }  
  10.   
  11. /* 
  12. ** return a random real in the interval [a, b] (also [a, b)) 
  13. */  
  14. double uniform_real(double a, double b) {  
  15.     static std::default_random_engine e{std::random_device{}()};  
  16.     static std::uniform_real_distribution<double> u;  
  17.   
  18.     return u(e, decltype(u)::param_type(a, b));  
  19. }  

C/C++ 中随机数的用法

标签:style   blog   http   io   ar   color   os   sp   for   

原文地址:http://www.cnblogs.com/yuyanbian/p/4127562.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!