室友去面试得到了这个:
规则:
允许使用 rand();
RAND_MAX = 32 767;
不使用除法或模数;
TODO: 编写一个函数,该函数接受一个 int 参数并返回 0 - 参数范围内的 int。
头疼,睡不着。任何帮助表示赞赏。谢谢
室友去面试得到了这个:
规则:
允许使用 rand();
RAND_MAX = 32 767;
不使用除法或模数;
TODO: 编写一个函数,该函数接受一个 int 参数并返回 0 - 参数范围内的 int。
头疼,睡不着。任何帮助表示赞赏。谢谢
几种可能:
范围转置方法:int r = rand() * 0.00003051855095 * n;
“随机排序”方法:int r; do { r = random(); } while (r >= n);
BSD方法:uint32_t r = arc4random_uniform(n);
等等等等等等。
在我的公共领域randlib中,我没有浮点,没有除法,没有乘法,只是位掩码和拒绝采样,如下所示:
int ojr_rand(ojr_generator *g, int limit) {
int v, m = limit - 1;
m |= m >> 1;
m |= m >> 2;
m |= m >> 4;
m |= m >> 8; // m is smallest ((power of 2) - 1) > limit
do {
v = m & NEXT16(g); // 16-bit random number
} while (v >= limit);
return v;
}
在最坏的情况下(限制是二加一的幂),这可以拒绝接近 50% 的生成数字,但它仍然比大多数快速 RNG 的除法或浮动数学要快,并且在一般情况下要快得多。此外,与浮点数学或 mod 不同,它是精确的,这意味着如果您要求限制为 3,那么您得到的值 0、1 和 2 的概率完全相等,而不仅仅是近似相等。
如果允许 c++11,则会提供一个随机标头,这使得这变得微不足道:
#include <random>
#include <iostream>
int Roll(int Max)
{
if(Max>32767)
Max=32767;
std::random_device generator;
std::uniform_int_distribution<int> distribution(0,Max);
return distribution(generator);
}
int main()
{
std::cout << Roll(10) << std::endl
<< Roll(10) << std::endl
<< Roll(999999) << std::endl;
}
更多详情请访问:http ://en.cppreference.com/w/cpp/numeric/random
这假定 RAND_MAX 是由您的问题而不是由 C 标准提供的,当然您可以使用提供的常量,有关详细信息,请参阅:http ://en.cppreference.com/w/cpp/numeric/random/RAND_MAX
do { r = random();} while (r >= max_rand);
起初我认为乘以分数会起作用,但从数学的角度来看,这可能被认为是作弊。
int getRand(int max)
{
int val = rand();
while (val > max)
{
val -= max + 1;
}
return val;
}
这显然会通过计数值 <=RAND_MAX % max
比其他所有值多一次但rand() % max
有同样的问题而略有偏差,所以我认为这个错误是可以接受的(对于max
<<MAX_RAND
的值,错误是微不足道的)。