代码:
int random = (rand() % 7 + 1)
if (random == 1) { } // num 1
else if (random == 2) { } // num 2
else if (random == 3 || random == 4) { } // num 3
else if (random == 5 || random == 6) { } // num 4
else if (random == 7) { } // num 5
基本上我希望这些数字中的每一个都具有以下几种概率: 1:1/7 2:1/7 3:2/7 4:2/7 5:1/7
这段代码会给我正确的结果吗?即如果这是无限次运行,我会得到合适的频率吗?这样做的方法不那么冗长吗?
答案 0 :(得分:7)
不是,它实际上略有偏离,因为rand()的工作方式。特别是,rand返回[0,RAND_MAX]范围内的值。假设RAND_MAX为10。然后rand()将给出0 ... 10,并将它们(按模数)映射到:
0 → 0
1 → 1
2 → 2
3 → 3
4 → 4
5 → 5
6 → 6
7 → 0
8 → 1
9 → 2
10 → 3
注意0-3比4-6更常见;这是随机数生成的偏差。 (你也加1,但这只是改变了它。)
RAND_MAX当然不是10,但它也可能不是7(减1)的倍数。最有可能是两个人的力量。所以你会有一些偏见。
我建议使用Boost Random Number Library,它可以为您提供一个随机数生成器,在没有偏差的情况下产生1-7。另请参阅bames53's answer using C++11,如果您的代码只需要针对C ++ 11平台,这是正确的方法。
答案 1 :(得分:2)
另一种方式:
float probs[5] = {1/7.0f, 1/7.0f, 2/7.0f, 2/7.0f, 1/7.0f};
float sum = 0;
for (int i = 0; i < 5; i++)
sum += probs[i]; /* edit */
int rand_M() {
float f = (rand()*sum)/RAND_MAX; /* edit */
for (int i = 0; i < 5; i++) {
if (f <= probs[i]) return i;
f -= probs[i];
}
return 4;
}
答案 2 :(得分:2)
int toohigh = RAND_MAX - RAND_MAX%7;
int random;
do {
random = rand();
while (random >= toohigh); //should happen ~0.03% of the time
static const int results[7] = {1, 2, 3, 3, 4, 4, 5};
random = results[random%7];
即使rand
可以处理,并且没有大的if
开关,也应该为数字提供分布。
注意这确实有一个理论上可能的无限循环,但它在循环中保持均匀的统计几率是微不足道的。它停留在循环两次的几率非常接近赢得加州超级乐透奖金的几率。即使地球上的每个人都有五个随机数,它也可能不会在循环中停留三次。 (假设一个完美的RNG。)
答案 3 :(得分:2)
假设rand()
是好的,那么你的代码只会对较低的X数字产生很小的偏差,其中X是RAND_MAX%7。你很可能不会得到所需的赔率rand()
的实施质量。如果您发现情况就是这样,那么您将需要使用替代随机数生成器。
C ++ 11引入了标题<random>
,其中包含多个质量RNG。这是一个例子:
#include <random>
#include <functional>
auto rand = std::bind(std::uniform_int_distribution<int>(1,7),std::mt19937());
鉴于此,当您致电rand()
时,您将获得1到7的数字,每个数字概率相等。 (如果针对不同的质量和速度特性,您可以选择不同的引擎。)然后,您可以使用它来实现您的示例当前与std::rand()
一起使用的if-else条件。但是<random>
允许您使用其中一个非均匀分布做得更好。在这种情况下,您想要的是discrete_distribution
。此分布允许您明确说明从0到n的每个值的权重。
// the random number generator
auto _rand = std::bind(std::discrete_distribution<int>{1./7.,1./7.,2./7.,2./7.,1./7.},std::mt19937());
// convert results of RNG from the range [0-4] to [1-5]
auto rand = [&_rand]() { return _rand() +1; };
答案 4 :(得分:-1)
rand返回伪 - 随机整数:
请注意,此模运算不会生成真正的 跨度中均匀分布的随机数(因为在大多数情况下) 较低的数字稍微可能),但通常是好的 近似短跨度。
现在,关于不那么漫长的方式,你可以使用switch-case构造,或一系列conditional operators ?:
(这将使你的代码简短且不可读:)。