大家在写 C/C++ 程序时,难免会遇到要求获取某个范围内的随机数,我查阅了一些资料后,总结如下。本文分两部分,先介绍 C 语言中与随机数相关的两个函数 srand 和 rand,后介绍 C++ 中的 random 库,每一部分最后会给出生成特定范围内的随机数模板供参考。

1 C 语言中的 srand 和 rand

1.1 实现

下面是 VC 的实现,GCC 的实现比 VC 的复杂,但基本原理是一样的。
[cpp] view plaincopyprint?
  1. #define RAND_MAX 32767  // in <stdlib.h>
  2. unsigned long _Randseed = 1;    // global seed
  3. void srand(unsigned int seed) {
  4. _Randseed = seed;
  5. }
  6. int rand(void) {
  7. _Randseed = _Randseed * 1103515245 + 12345;
  8. return ((unsigned int)(_Randseed >> 16) & RAND_MAX);
  9. }

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

1.2 time

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

[cpp] view plaincopyprint?
  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 这个函数,它的函数原型如下:

[cpp] view plaincopyprint?
  1. time_t time(time_t *timer);

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

1.3 my rand

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

[cpp] view plaincopyprint?
  1. int g_is_first = 1;
  2. /*
  3. ** return a random integer in the interval
  4. ** [a, b]
  5. */
  6. int uniform_int(int a, int b) {
  7. if (g_is_first) {
  8. g_is_first = 0;
  9. srand((unsigned int)time(NULL));
  10. }
  11. return (int)((double)rand() / ((RAND_MAX + 1.0) / (b - a + 1.0)) + a);
  12. }
  13. /*
  14. ** return a random real in the interval
  15. ** [a, b] (also [a, b))
  16. */
  17. double uniform_real(double a, double b) {
  18. if (g_is_first) {
  19. g_is_first = 0;
  20. srand((unsigned int)time(NULL));
  21. }
  22. return (double)rand() / ((double)RAND_MAX / (b - a)) + a;
  23. }

为了保证 srand 函数只执行一次,这里用了全局标志 g_is_first。其实最好在头文件中定义接口,在源文件中实现,这里为了使用方便就全放一起了。当要求的随机数范围过大时,uniform_int 和 uniform_real 貌似有 bug。

2 C++ 中的 random 库

在 random 库中有随机数发生器(random engine/generator)和分布(distribution),它们的具体用法我就不在这说了。我个人认为 engine 存储了种子,将 C 语言中的全局种子封装起来了。uniform distribution 中只存储了最大值和最小值(即平均分布的两个参数)。还有个真正的 engine 叫 std::random_device,它根据机器的各种实时参数产生随机数,标准规定它的实现是可选的,有的编译器(如 MinGW)目前不支持,产生的还是伪随机数,不过 VC 及 Linux 平台上的 GCC 是支持的,下面的程序假设用户的编译器支持。
[cpp] view plaincopyprint?
  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. return u(e, decltype(u)::param_type(a, b));
  8. }
  9. /*
  10. ** return a random real in the interval [a, b] (also [a, b))
  11. */
  12. double uniform_real(double a, double b) {
  13. static std::default_random_engine e{std::random_device{}()};
  14. static std::uniform_real_distribution<double> u;
  15. return u(e, decltype(u)::param_type(a, b));
  16. }

最后,还有个问题没搞懂:能否始终用 random_device 代替 default_random_engine ?它们的区别是什么?

参考资料

[1] C 标准库
[2] C 和指针
[3] 随机数是骗人的,.Net、Java、C为我作证
[4] How to generate a random number in C?
[5] Generate random numbers uniformly over an entire range
[6] Generate a random number within range?
[7] C++ random float number generation
[8] C++ Primer
[9] How to make sure a function is only called once

from: http://blog.csdn.net/Justme0/article/details/41547761

C/C++ 中生成特定范围内的随机数相关推荐

  1. 在JavaScript中生成特定范围内的随机整数?

    如何可以生成两个指定的变量之间的随机整数在JavaScript中,例如x = 4和y = 8将输出任何的4, 5, 6, 7, 8 ? #1楼 对于具有范围的随机整数,请尝试: function ra ...

  2. 如何在Java中生成特定范围内的随机整数?

    如何生成特定范围内的随机int数值? 我已经尝试了以下方法,但是这些方法不起作用: 尝试1: randomNum = minimum + (int)(Math.random() * maximum); ...

  3. python从random生成列表_详解Python利用random生成一个列表内的随机数

    详解Python利用random生成一个列表内的随机数 首先,需要导入random模块: import random 随机取1-33之间的1个随机数,可能重复: random.choice(range ...

  4. Vb生成一定范围内的随机数(含小数部分)

    下面这个函数,可以生成一定范围内的随机数,可以指定小数位数. 比如 RndBetween (10, 99, 2) 返回 [10.00~99.00] 范围内的随机数. Function RndBetwe ...

  5. java中产生指定范围内的随机数

    1.Math.random()方法返回一个[0.0 , 1.0)的伪随机double类型的随机数 2.符合在[min,max]范围内的整数 int num = min + (int)(Math.ran ...

  6. java中生成1000~10000之间的随机数

    要生成在[min,max]之间的随机整数,可使用Random类进行相关运算: Random random = new Random(); int s = random.nextInt(max)%(ma ...

  7. C++生成指定范围内的随机数

    代码 rand()% 3 : 3就是范围,代表生成[0,3)之间的随机数 int main(){for (int i = 0; i < 20; i++) {switch (rand() % 3) ...

  8. BCB 生成某个范围内的随机数

    头文件: #include <Math.hpp> 代码: int xi = 0;             xi = RandomRange(10000000,99999999);//生成一 ...

  9. python随机生成数字列表_详解Python利用random生成一个列表内的随机数

    首先,需要导入random模块: import random 随机取1-33之间的1个随机数,可能重复: random.choice(range(1,34)) print得到一系列随机数,执行一次得到 ...

最新文章

  1. 使用XML作为配置表,WinForm程序读取配置表来动态显示控件
  2. 使用方差阈值过滤(VarianceThreshold)进行特征选择、删除方差低于某一阈值的特征、详解及实战
  3. MySQL的主从复制延迟问题
  4. github上的Lua in Erlang
  5. Atom.io设置ctrl+delete
  6. if you have something important on the clean my mac
  7. Jquery.load() 使用
  8. [Visual Studio+TFS--强大的项目管理工具]
  9. Java 设计模式 Day2 之面向抽象原则:接口(interface)的设计应用与抽象类的区别
  10. ubuntu同时装有MXNet和Caffe框架
  11. ZooKeeper 特点有哪些?
  12. 剑指Offer_12_矩阵中的路径(参考问题:马踏棋盘)
  13. 经典排序算法(十一)--堆排序Heap Sort
  14. mysql 全关联查询_Mysql 关联查询(内联、左联、右联、全联)
  15. z变换解差分方程例题_Z变换解差分方程的思考
  16. 2018年航空概论期末考试
  17. Matlab 黎卡提方程
  18. 整合营销系统推荐乐云seo_珠海整合营销【乐云seo】
  19. JS实现视频录制-以Cesium为例
  20. Laravel 7.x - 学习/实践

热门文章

  1. JS中map()与forEach()的用法
  2. SpringBoot Thymeleaf使用教程(实用版)
  3. TensorFlow学习笔记(二):快速理解Tutorial第一个例子-MNIST机器学习入门 标签: 机器学习SoftmaxTensorFlow教程 2016-08-02 22:12 3729人阅
  4. LambdaMART的源码分析:一(MART:回归树)
  5. 算法2:判断两个字符串内容是否相同
  6. jvm性能调优 - 10白话年轻代数据晋升老年代规则及老年代回收算法
  7. Java8 - 使用工厂方法 supplyAsync创建 CompletableFuture
  8. JVM - 一个案例反推不同JDK版本的intern机制以及intern C++源码解析
  9. Java学习笔记(八)--字符串生成器
  10. 学习笔记Hadoop(十)—— Hadoop基础操作(2)—— HDFS常用Shell操作