根据这些概率,这会给我合适的随机数吗?C++

Will this give me proper random numbers based on these probabilities? C++

本文关键字:随机数 C++ 概率      更新时间:2023-10-16

代码:

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/72:1/73:2/74:2/75:1/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随机数库,它可以为您提供一个随机数生成器,无偏差地生成1–7。还可以使用C++11查看bames53的答案,如果您的代码只需要针对C++11平台,那么这是正确的方法。

另一种方式:

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;
}

假设rand()是好的,那么您的代码只会对较低的X数字产生很小的偏差,其中X是RAND_MAX%7。由于rand()的实现质量的原因,您很可能无法获得所需的几率。如果你发现是这样的话,那么你会想要使用一个替代的随机数生成器。

C++11引入了报头CCD_ 3,其包括若干质量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; };
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。(

rand返回-随机整数:

请注意,这个模运算并没有生成真正的跨度中均匀分布的随机数(因为在大多数情况下较低的数字更有可能(,但这通常是一个好的短跨度的近似值。


现在,关于不那么长的方法,您可以使用switch-case构造,或一系列条件运算符?:(这将使您的代码变短且不可读:(。