RAND_MAX和UINT_MAX之间的差异会有所不同吗?

时间:2011-11-27 04:04:47

标签: c++ random bit-manipulation

我的作业涉及在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

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

2 个答案:

答案 0 :(得分:5)

您的问题围绕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

  2. (即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的特殊选择,您将获得梅森素数。

    3. 例如,一个常见的选择是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

      总而言之,回答你的问题:在大多数实现中你可以假设有一个简单的位移,但是,没有真正的保证。至少你应该在你的程序init上进行运行时测试。如果您正在使用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;
      }
      

答案 1 :(得分:3)

  

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

如果你的教授告诉你这样做,你应该这样做。当然,这不是加密力量,但是为了完成家庭作业,它会很好。

对于RAND_MAX 2^n - 1,我通常会这样认为。计算机生成随机数的方式是一次设定的位数,因此如果最大值不是2^n - 1,则不能返回范围内的所有数字,也不会浪费熵。

至于所有系统的差异是相同的,我强烈建议不要假设。在你的代码中,弄清楚每个位中有多少位,并动态地计算出如何移位。

你不能直接进入学校服务器,你最终会在这个服务器上运行吗?