【问题标题】:Will the difference between RAND_MAX and UINT_MAX vary?RAND_MAX 和 UINT_MAX 之间的差异会有所不同吗?
【发布时间】:2011-11-27 04:04:47
【问题描述】:

我的作业是在02^30 之间生成随机整数。现在,在过去我们了解到rand() 只返回最大为RAND_MAX 的整数,这小于UINT_MAX,并且我们可以使用位移来填充UINT_MAX 的容量。从我所做的一些阅读中(在这里,关于 SO),我意识到如果这些数字的分布对我很重要,这可能不是一个好主意。话虽如此,我的教授已经指定了这种方法。

我的问题是,移位多少? RAND_MAXUINT_MAX 之间的区别是否总是存在一个安全的常数来进行位移?或者是否需要进行一些初始探测以确定位移的数量?我是否应该继续移动一点点并检查UINT_MAX

我问的原因是,UINT_MAX 被定义为至少一个特定的数字(65535),但在我的机器上,UINT_MAX 要大得多(4294967295)。这让我担心我可能会在周末完成作业,到达学校后发现一切都不够好,无法提交。

谢谢!

参考资料:

我已经阅读了几个类似的问题,但无法从他们那里得到答案。

Is the value of RAND_MAX always (2^n)-1?

generating a random number within range 0 to n where n can be > RAND_MAX

实际上,上面的第二个问题让我质疑这样做的价值?

【问题讨论】:

  • 出于好奇,你上哪所学校?
  • 位于不列颠哥伦比亚省温哥华的兰加拉学院(加拿大)。 :)

标签: c++ random bit-manipulation


【解决方案1】:

您的问题集中在RAND_MAXUINT_MAX 之间是否存在位移。这归结为UINT_MAXRAND_MAX 是否为2^k - 1 形式的问题。 UINT_MAX 几乎肯定会在任何基于二进制数系统的计算机上。如果sizeof(int)=32 位然后k=32,如果sizeof(int)=64 bit 然后k=64,等等。现在我们可以考虑RAND_MAX。在大多数实现中,答案是RAND_MAX 几乎总是采用2^k - 1 的形式。为什么?我们需要考虑rand() 的大多数实现是如何实际工作的。

  1. rand() 通常使用线性同余生成器(请参阅http://en.wikipedia.org/wiki/Linear_congruential_generator 或 Knuth “计算机程序员的艺术第 2 部分:半数值算法”)。基本上一个随机数是一个带有seed的序列

    x(k+1) = ( a x(k) + c ) % m

(即 C 库存储最后一次迭代的 x(k),当您调用 rand() 时,它返回 x(k+1)

  1. 为了获得良好的质量,必须仔细选择生成器的参数(acm)。质量通常需要在序列自身重复之前多少次,等等。选择这些参数的一个紧张是使m 尽可能接近UINT_MAX,以免浪费潜在的随机位。如果您研究生成器,通常正确的选择是使m 略小于UINT_MAX。您还需要将m 设为素数。

  2. 通常您希望rand() 尽可能快,因此您希望这些操作便宜。要计算的最便宜的modfoo % (2^k - 1) 形式之一,因为它可以实现为foo & (1<<k-1)。对于k 的特殊选择,您将获得梅森素数。

例如,一个常见的选择是k=31,它产生素数2^31-1 = 2147483647。这是UINT_MAX=2^32-1 = 4294967295 的32 位整数的典型选择。对于 64 位数字,有一个 UINT_MAX=2^64-1=18446744073709551615,而 RAND_MAX 的选择是 2^61-1 = 2305843009213693951

总而言之,回答您的问题:在大多数实现中,您可以假设有一个简单的位移,但是,并没有真正的保证。至少你应该在你的程序初始化时做一个运行时测试。如果您使用 C++,更好的做法是使用 static_assert 在编译时检测您的假设是否正确,如果不正确则无法编译。 Boost 有这样一个静态断言,就像最近批准的标准 C++11 一样......即可以做到(尽管编写 is_power_of_two_minus_one 的静态版本可能需要一些工作):

unsigned int myrand()
{
        static_assert(sizeof(int)==4,"sizeof(unsigned int) != 4");
        static_assert(is_power_of_two_minus_one(RAND_MAX),"RAND_MAX not a power of two minus one");
        static_assert(is_power_of_two_minus_one(UINT_MAX),"UINT_MAX not power of two minus one");
        unsigned int raw_rand=rand();
        // do your bit shift to adjust raw_rand
        return raw_rand;
}

【讨论】:

  • 哇。我认为在一周内您将拥有 UINT_MAX 声誉。这完全回答了我所有的担忧,如果我可以投票 100 次,我可能会。谢谢!另外:很棒的简历!
  • constexpr bool is_power_of_two_minus_one(unsigned long long n) { return ( n & (n+1) ) == 0; } 怎么样?
【解决方案2】:

实际上,上面的第二个问题让我质疑这样做的价值?

如果你的教授告诉你这样做,你应该这样做。这当然不是加密强度,但对于家庭作业来说,它会很好。

对于RAND_MAX2^n - 1,我通常会这样认为。计算机生成随机数的方式是一次设置一组位数,因此如果最大值不是2^n - 1,则不是该范围内的所有数字都可以返回,否则熵将被浪费。

至于所有系统上的差异都相同,我强烈建议不要假设。在您的代码中,找出每个位中有多少位,并动态地找出如何移位。

你不能通过 ssh 进入你将(最终)运行它的学校服务器吗?

【讨论】:

  • 好吧,rand 永远不会是加密安全的。
猜你喜欢
  • 2012-10-27
  • 1970-01-01
  • 2014-02-11
  • 2010-09-20
  • 2015-03-26
  • 2010-12-17
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多