我的作业涉及在0
和2^30
之间制作随机整数。现在,在过去,我们已经了解到rand()
仅返回最多RAND_MAX
的整数,这小于UINT_MAX
,并且我们可以使用位移来填充UINT_MAX
容量。从我已经完成的一些阅读(这里,在SO上),我意识到,如果这些数字的分布对我很重要,这可能不是一个好主意。话虽如此,我的教授已经指明了这种方法。
我的问题是,转移多少钱? RAND_MAX
和UINT_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
实际上,上面的第二个问题让我质疑这样做的价值吗?
答案 0 :(得分:5)
您的问题围绕RAND_MAX
和UINT_MAX
之间是否有一点转换。这减少了UINT_MAX
和RAND_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()
的大多数实现如何实际工作。
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)
)
要获得高质量,必须仔细选择生成器(a
,c
和m
)的参数。质量通常需要在序列重复之前多少次等。选择这些参数的一个紧张是使m
尽可能接近UINT_MAX
,以避免浪费潜在的随机位。如果您研究生成器,通常正确的选择是使m
略小于UINT_MAX
。您还需要将m
作为素数。
通常您希望rand()
尽可能快,因此您希望这些操作便宜。要计算的最便宜的mod
是foo % (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
。
总而言之,回答你的问题:在大多数实现中你可以假设有一个简单的位移,但是,没有真正的保证。至少你应该在你的程序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
,则不能返回范围内的所有数字,也不会浪费熵。
至于所有系统的差异是相同的,我强烈建议不要假设。在你的代码中,弄清楚每个位中有多少位,并动态地计算出如何移位。
你不能直接进入学校服务器,你最终会在这个服务器上运行吗?