Jer*_*fin 67
实际上,这比大多数人意识到的要难得多:
int rand_lim(int limit) {
/* return a random number between 0 and limit inclusive.
*/
int divisor = RAND_MAX/(limit+1);
int retval;
do {
retval = rand() / divisor;
} while (retval > limit);
return retval;
}
Run Code Online (Sandbox Code Playgroud)
尝试仅使用%(或等效地/)获得范围内的数字几乎不可避免地引入偏差(即,某些数字将比其他数字更频繁地生成).
至于为什么使用%产生偏差结果:除非你想要的范围是RAND_MAX的除数,否则偏差是不可避免的.如果从小数字开始,很容易理解为什么.考虑服用10块糖果并试图在三个孩子之间均匀分配.显然它是不可能的 - 如果你分发所有的糖果,你可以得到的最接近的是两个孩子得到三块糖果,其中一个得到四块糖果.
所有孩子只有一种方法可以获得相同数量的糖果:确保你根本不分发最后一块糖果.
为了将其与上面的代码联系起来,让我们首先将糖果从1到10以及从1到3的孩子编号.最初的分工说,因为有三个孩子,我们的除数是三.然后我们从桶中取出一个随机的糖果,看看它的数字并除以三并将它交给那个孩子 - 但如果结果大于3(即我们选择了10号糖果)我们就是不把它拿出来 - 我们丢弃它并挑出另一种糖果.
当然,如果您正在使用C++的现代实现(即支持C++ 11或更新版本的C++),您通常应该使用distribution标准库中的一个类.上面的代码最接近std::uniform_int_distribution,但标准库还包括uniform_real_distribution许多非均匀分布的类(伯努利,泊松,正常,也许还有其他一些我目前不记得的).
int rand_range(int min_n, int max_n)
{
return rand() % (max_n - min_n + 1) + min_n;
}
Run Code Online (Sandbox Code Playgroud)
对于分数:
double rand_range(double min_n, double max_n)
{
return (double)rand()/RAND_MAX * (max_n - min_n) + min_n;
}
Run Code Online (Sandbox Code Playgroud)