这会根据这些概率给出适当的随机数吗? C ++

时间:2011-11-29 19:44:27

标签: c++ random probability

代码:

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

这段代码会给我正确的结果吗?即如果这是无限次运行,我会得到合适的频率吗?这样做的方法不那么冗长吗?

5 个答案:

答案 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 ?:(这将使你的代码简短且不可读:)。