【问题标题】:Is the value of RAND_MAX always (2^n)-1?RAND_MAX 的值是否总是 (2^n)-1?
【发布时间】:2011-06-24 03:51:08
【问题描述】:

我对 C++ 很感兴趣,但我怀疑它只是导入了 C 标准定义。我相信标准所说的答案是否定的,但我最感兴趣的是实践中的答案。

如果 RAND_MAX 始终为 (2^n)-1(其中 n 是某个自然数 - 实际上是随机数中随机二进制数字的数量),则可以简化处理最近从 MinGW 移动代码的问题GCC 到 Linux GCC。 RAND_MAX 似乎更大(我没有检查,但可能等于 INT_MAX 或任何符号),所以一些旧的天真编写的 RAND_MAX-isn't-big-enough-so-work-around-it 代码适得其反。现在我需要决定我需要这个库的通用性,考虑到编写正确处理溢出可能性的代码的复杂性,而不会对例如int 的宽度。

无论如何,是否有任何合理广泛使用的 C++ 编译器使用 (2^n)-1 以外的东西来表示 RAND_MAX?

另外,我是否更正了 ((RAND_MAX | (RAND_MAX >> 1)) == RAND_MAX) 对于某些无符号整数 n 始终且仅当 RAND_MAX 等于 ((2^n)-1) 时才为真。我相信 RAND_MAX 在技术上是一个 int,但是有一个负值或小数值是没有意义的,所以我认为我可以放心地忽略这些。摆弄比特通常不会打扰我,但我一直认为表达式看起来不对,我不知道为什么。

最后,虽然在找到自己的可行解决方案之前我不会感到高兴,但我应该将什么用于随机数而不是自己编写?我需要 0

有 Boost 或 C++0x 的东西吗?

编辑

按照页面侧面“相关”位中的内容显示,确实有一种方法可以在 boost 中获取具有给定下限和上限的随机数。

【问题讨论】:

  • 对于我们这些对此问题感兴趣的人,您能否澄清/编辑 2^n - 1 中变量 n 的含义?

标签: c++ random


【解决方案1】:

我不知道RAND_MAX 上的保证是什么,但如果可能的话,您最好避免使用它,因为周围有很多损坏的实现,而且它在当今的应用程序中开始循环很快。 here 描述了获得均匀分布。

我推荐Boost.RandomMersenne twister 生成器代表了速度、内存使用和质量之间的良好折衷。

【讨论】:

  • 我已经有一个 Mersenne twister 实现 - 没有充分的理由,只是在一本书中介绍了它。当然,一个好的库版本会更实用。感谢您的提示。
  • 如果我是你,我会切换到 Boost;它干净地将 PRNG 与概率分布分开,并包含一个 random_device 类用于正确播种 (boost.org/doc/libs/release/doc/html/boost/random_device.html)。
  • 接受了大约 80%,因为对 rand 链接的误解 - Boost 点更实用,但该链接非常有趣。
  • 顺便说一句 - random_device 点很受期待。除了玩游戏之外,我从未真正使用过我的 MT 的一个原因是“好的,那么我该如何正确地播种”问题。我想如果我做得不对,那么改变任何东西都没有多大意义。
  • 我觉得 Mersenne twister 有点老了,现在我会使用 SMFT:math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html
【解决方案2】:
  • 我不知道任何 RAND_MAX 不小于 2 的幂的任何实现,但这不是标准规定的;

  • ((RAND_MAX | (RAND_MAX >> 1)) == RAND_MAX) 确实是一种测试 RAND_MAX 是否小于二的幂的方法。

  • 我正在使用

    int alea(int n){ 
      assert (0 < n && n <= RAND_MAX); 
      int partSize = 
        n == RAND_MAX ? 1 : 1 + (RAND_MAX-n)/(n+1); 
      int maxUsefull = partSize * n + (partSize-1); 
      int draw; 
      do { 
        draw = rand(); 
      } while (draw > maxUsefull); 
      return draw/partSize; 
    }
    

使来自 rand() 的随机数尽可能均匀分布。

【讨论】:

  • 我不能完全使用该功能,因为 RAND_MAX 太小问题在 Windows 上仍然存在。也就是说,我可以有条件地编译以在它和 use-two-randoms-to-make-one 版本之间进行选择(现有代码与您的代码非常相似)。无论如何,这就是我暂时关闭错误的方法 - 似乎只是作弊。
【解决方案3】:

对于rand 的实现,它使用(a 的变体)线性同余生成器(大部分),那么 RAND_MAX 将是一个素数,不一定是 2n - 1 的形式(“梅森素数”)。

另外,231-1 是素数,但如果 n 不是素数,则 2n - 1 不是素数。

(事实上,如果 n = ab,那么 2n - 1 = (2a - 1)(1 + 2b + 22b + ...) )

在 264 附近,唯一的梅森素数是 261 - 1。

如果你对随机数生成有任何半严肃的要求,你应该真正避免使用线性同余生成器。实际上,我想说的是,除了俄罗斯方块游戏之外,您应该避免使用 C 库中的rand()

【讨论】:

  • 有趣。 OTOH - “俄罗斯方块”并没有真正离目标很远 - 对很多人来说,不仅仅是我。开发安全关键加密库或其他您真正关心该生成器真正随机性的应用程序的人数可能与例如希望通过一些基于随机测试数据的测试来补充回归测试的人数或编写简单游戏的人数。
  • @Steve314:线性组合。生成器有严重的缺陷,即使是最简单的数学应用也无法使用。参见例如。 javamex.com/tutorials/random_numbers/lcg_planes.shtml 明白我的意思。
  • 关键词是“数学应用程序”,我可以接受即使对于一些非常简单的应用程序,您可能需要更强大的生成器。我将添加“工程模拟”,这也可能属于我的“您真正关心的其他应用程序”的范畴。但说真的 - 对于许多程序员来说,我们很少需要随机数,而当我们这样做时,rand 几乎总是足够好。有时,即使“在最后一个数字上加一”也足以生成一些任意数据,省去了播种和查找要包含的正确标题的小麻烦。
  • @Alexande - 也就是说,当更多人开始使用 C++0x 标准库随机数支持时,世界可能会变得更美好。不过,考虑到对各种发行版和可能其他好东西的支持,更强大的(默认?)随机数生成器更像是一个额外的好处。
【解决方案4】:

在 GCC (4.6) RAND_MAX = 0x7FFFFFFF (31bit) 在 MS Visual Studio (2012) RAND_MAX = 0x7FFF (15bit)

【讨论】:

  • 这没有回答问题。它显示了 2 个示例,但这真的适用于所有编译器吗?有标准保证吗?
【解决方案5】:

在 Embacadero C++ Builder 中,stdlib.h 中定义了两个变量:

/* Maximum value returned by "rand" function*/
#define RAND_MAX  0x7FFFU

/* Maximum value returned by "_lrand" function (also used by random() macro)*/
#define LRAND_MAX 0x7FFFFFFFU

【讨论】:

  • 显示来自特定编译器的值并不能回答问题
【解决方案6】:

在标准 GNU 头文件 stdlib.h 中,有一个 RAND_MAX 的定义,它应该是您系统中的唯一定义:

#define RAND_MAX    2147483647

值 2147483647 = 0x7fffffff 是最大的 un有符号 32 位整数。

在 stdlib.h 中定义的 rand 函数在标准 GNU 环境中是可靠的,但有一个警告:多线程 (pthread) 环境需要同步 pthread 代码以保护 rand()、srand() 和rand_r() 调用,因为它们不可重入。有关说明,请参阅 man page for srand

RAND_MAX 不应在系统的其他任何地方定义。如果您在 stdlib.h 之外的某个地方看到 RAND_MAX 的不同值或看到 RAND_MAX 的定义,那么这一定是非标准、不可移植的环境。 Windows 因难以实现标准化和可移植性而臭名昭著(例如套接字实现和 API)。

【讨论】:

    【解决方案7】:

    根据 ISO C(至少 C99 到 C17)和 POSIX(第 7 期,2016 版),RAND_MAX 至少应为 32767,即 215-1,并且有没有其他限制。

    在 GNU/Linux 下,RAND_MAX 在所有架构上都保证为 2147483647 = 231-1,以与关于 random() 函数的 POSIX 保持一致:POSIX 指定返回值在 0 到 231-1 的范围内,Linux random(3) 手册页记录了从 0 到 RAND_MAX 的范围。

    【讨论】:

    • 最初的问题现在已经无关紧要了——它在 2011 年被问到并专注于 C++,但 C++ 在 2011 年标准中获得了用于随机数的新库(基于 Boost 随机库 IIRC)。当然,C++ 仍然导入大部分 C 标准,这是来自 C 的相关信息。rand 仍然包含在其中,尽管强烈建议不要使用它——例如std::random_shuffle(在幕后使用了 rand)在 C++14 中被弃用,并被 std::shuffle(它有一个额外的“统一随机生成器”参数)取代。
    • @Steve314 但是,如果不想使用外部库,这个问题仍然与 C 有关。
    • @chux-ReinstateMonica RAND_MAX &lt;= INT_MAX 不是限制,只是rand 函数返回int 的结果。
    • 好吧,很公平,
    猜你喜欢
    • 1970-01-01
    • 2015-02-26
    • 2012-10-27
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 1970-01-01
    • 2013-05-15
    相关资源
    最近更新 更多